media: rockchip: update isp ispp work mode

Isp transfer to ispp support quick or one frame mode
date support fbc or no fbc, set mode to node before
open ispp dev, default is one frame yuv422 fbc mode.
For the mode:
BIT(2): enable quick
BIT(1): enable yuv422
BIT(0): enable fbc
For example to quick yuv422 fbc mode:
echo 7 > /sys/module/video_rkispp/parameters/mode

Change-Id: I1c92a69c245cbdf85ff6bc9ab23c6e46c51311c0
Signed-off-by: Cai YiWei <cyw@rock-chips.com>
This commit is contained in:
Cai YiWei
2020-04-30 20:23:19 +08:00
committed by Tao Huang
parent 7e53f0162c
commit 9ef4ce87f2
24 changed files with 2003 additions and 1061 deletions

View File

@@ -13,5 +13,5 @@ video_rkisp-objs += rkisp.o \
capture.o \
dmarx.o \
csi.o \
mpfbc.o \
bridge.o \
isp_mipi_luma.o

View File

@@ -0,0 +1,772 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <media/v4l2-common.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf2-dma-contig.h>
#include <linux/dma-iommu.h>
#include <linux/rk-camera-module.h>
#include "dev.h"
#include "regs.h"
static inline
struct rkisp_bridge_buf *to_bridge_buf(struct rkisp_ispp_buf *dbufs)
{
return container_of(dbufs, struct rkisp_bridge_buf, dbufs);
}
static void update_mi(struct rkisp_bridge_device *dev)
{
void __iomem *base = dev->ispdev->base_addr;
struct rkisp_bridge_buf *buf;
u32 val;
if (dev->nxt_buf) {
buf = to_bridge_buf(dev->nxt_buf);
val = buf->dummy[GROUP_BUF_PIC].dma_addr;
writel(val, base + dev->cfg->reg.y0_base);
val += dev->cfg->offset;
writel(val, base + dev->cfg->reg.uv0_base);
val = buf->dummy[GROUP_BUF_GAIN].dma_addr;
writel(val, base + dev->cfg->reg.g0_base);
}
v4l2_dbg(3, rkisp_debug, &dev->sd,
"%s pic(shd:0x%x base:0x%x) gain(shd:0x%x base:0x%x)\n",
__func__,
readl(base + dev->cfg->reg.y0_base_shd),
readl(base + dev->cfg->reg.y0_base),
readl(base + dev->cfg->reg.g0_base_shd),
readl(base + dev->cfg->reg.g0_base));
}
static int frame_end(struct rkisp_bridge_device *dev)
{
struct v4l2_subdev *sd = v4l2_get_subdev_hostdata(&dev->sd);
unsigned long lock_flags = 0;
if (dev->cur_buf && dev->nxt_buf) {
dev->cur_buf->frame_id = rkisp_dmarx_get_frame_id(dev->ispdev) + 1;
v4l2_subdev_call(sd, video, s_rx_buffer, dev->cur_buf, NULL);
dev->cur_buf = NULL;
}
if (dev->nxt_buf) {
dev->cur_buf = dev->nxt_buf;
dev->nxt_buf = NULL;
}
spin_lock_irqsave(&dev->buf_lock, lock_flags);
if (!list_empty(&dev->list)) {
dev->nxt_buf = list_first_entry(&dev->list,
struct rkisp_ispp_buf, list);
list_del(&dev->nxt_buf->list);
}
spin_unlock_irqrestore(&dev->buf_lock, lock_flags);
update_mi(dev);
return 0;
}
static int config_gain(struct rkisp_bridge_device *dev)
{
void __iomem *base = dev->ispdev->base_addr;
struct rkisp_bridge_buf *buf;
u32 val;
dev->cur_buf = list_first_entry(&dev->list,
struct rkisp_ispp_buf, list);
list_del(&dev->cur_buf->list);
if (!list_empty(&dev->list)) {
dev->nxt_buf = list_first_entry(&dev->list,
struct rkisp_ispp_buf, list);
list_del(&dev->nxt_buf->list);
}
if (dev->nxt_buf && (dev->work_mode & ISP_ISPP_QUICK)) {
buf = to_bridge_buf(dev->nxt_buf);
val = buf->dummy[GROUP_BUF_GAIN].dma_addr;
writel(val, base + dev->cfg->reg.g1_base);
mi_wr_ctrl2(base, SW_GAIN_WR_PINGPONG);
}
buf = to_bridge_buf(dev->cur_buf);
val = buf->dummy[GROUP_BUF_GAIN].dma_addr;
writel(val, base + dev->cfg->reg.g0_base);
val = dev->cur_buf->dbuf[GROUP_BUF_GAIN]->size;
writel(val, base + MI_GAIN_WR_SIZE);
val = ALIGN((dev->crop.width + 3) >> 2, 16);
writel(val, base + MI_GAIN_WR_LENGTH);
mi_wr_ctrl2(base, SW_GAIN_WR_AUTOUPD);
return 0;
}
static int config_mpfbc(struct rkisp_bridge_device *dev)
{
void __iomem *base = dev->ispdev->base_addr;
struct rkisp_bridge_buf *buf;
u32 h = ALIGN(dev->crop.height, 16);
u32 val, ctrl = 0;
if (dev->work_mode & ISP_ISPP_QUICK) {
isp_set_bits(base + CTRL_SWS_CFG,
0, SW_ISP2PP_PIPE_EN);
ctrl = SW_MPFBC_MAINISP_MODE;
if (dev->nxt_buf) {
ctrl |= SW_MPFBC_PINGPONG_EN;
buf = to_bridge_buf(dev->nxt_buf);
val = buf->dummy[GROUP_BUF_PIC].dma_addr;
writel(val, base + dev->cfg->reg.y1_base);
val += dev->cfg->offset;
writel(val, base + dev->cfg->reg.uv1_base);
}
}
buf = to_bridge_buf(dev->cur_buf);
val = buf->dummy[GROUP_BUF_PIC].dma_addr;
writel(val, base + dev->cfg->reg.y0_base);
val += dev->cfg->offset;
writel(val, base + dev->cfg->reg.uv0_base);
writel(0, base + ISP_MPFBC_VIR_WIDTH);
writel(h, base + ISP_MPFBC_VIR_HEIGHT);
mp_set_data_path(base);
isp_set_bits(base + MI_WR_CTRL, 0,
CIF_MI_CTRL_INIT_BASE_EN |
CIF_MI_CTRL_INIT_OFFSET_EN);
isp_set_bits(base + MI_IMSC, 0,
dev->cfg->frame_end_id);
ctrl |= (dev->work_mode & ISP_ISPP_422) | SW_MPFBC_EN;
writel(ctrl, base + ISP_MPFBC_BASE);
return 0;
}
static void disable_mpfbc(void __iomem *base)
{
isp_clear_bits(base + ISP_MPFBC_BASE, SW_MPFBC_EN);
}
static struct rkisp_bridge_ops mpfbc_ops = {
.config = config_mpfbc,
.disable = disable_mpfbc,
.is_stopped = is_mpfbc_stopped,
};
static struct rkisp_bridge_config mpfbc_cfg = {
.frame_end_id = MI_MPFBC_FRAME,
.reg = {
.y0_base = ISP_MPFBC_HEAD_PTR,
.uv0_base = ISP_MPFBC_PAYL_PTR,
.y1_base = ISP_MPFBC_HEAD_PTR2,
.uv1_base = ISP_MPFBC_PAYL_PTR2,
.g0_base = MI_GAIN_WR_BASE,
.g1_base = MI_GAIN_WR_BASE2,
.y0_base_shd = ISP_MPFBC_HEAD_PTR,
.uv0_base_shd = ISP_MPFBC_PAYL_PTR,
.g0_base_shd = MI_GAIN_WR_BASE_SHD,
},
};
static int config_mp(struct rkisp_bridge_device *dev)
{
void __iomem *base = dev->ispdev->base_addr;
struct rkisp_bridge_buf *buf;
u32 val;
if (dev->work_mode & ISP_ISPP_QUICK) {
isp_set_bits(base + CTRL_SWS_CFG, 0,
SW_ISP2PP_PIPE_EN);
if (dev->nxt_buf) {
buf = to_bridge_buf(dev->nxt_buf);
val = buf->dummy[GROUP_BUF_PIC].dma_addr;
writel(val, base + dev->cfg->reg.y1_base);
val += dev->cfg->offset;
writel(val, base + dev->cfg->reg.uv1_base);
isp_set_bits(base + CIF_MI_CTRL, 0,
CIF_MI_MP_PINGPONG_ENABLE);
}
}
buf = to_bridge_buf(dev->cur_buf);
val = buf->dummy[GROUP_BUF_PIC].dma_addr;
writel(val, base + dev->cfg->reg.y0_base);
val += dev->cfg->offset;
writel(val, base + dev->cfg->reg.uv0_base);
writel(dev->cfg->offset, base + CIF_MI_MP_Y_SIZE_INIT);
val = dev->cur_buf->dbuf[GROUP_BUF_PIC]->size - dev->cfg->offset;
writel(val, base + CIF_MI_MP_CB_SIZE_INIT);
writel(0, base + CIF_MI_MP_CR_SIZE_INIT);
writel(0, base + CIF_MI_MP_Y_OFFS_CNT_INIT);
writel(0, base + CIF_MI_MP_CB_OFFS_CNT_INIT);
writel(0, base + CIF_MI_MP_CR_OFFS_CNT_INIT);
mp_set_data_path(base);
mp_mi_ctrl_set_format(base, MI_CTRL_MP_WRITE_YUV_SPLA);
writel(dev->work_mode & ISP_ISPP_422, base + ISP_MPFBC_BASE);
isp_set_bits(base + MI_WR_CTRL, 0,
CIF_MI_CTRL_INIT_BASE_EN |
CIF_MI_CTRL_INIT_OFFSET_EN);
isp_set_bits(base + MI_IMSC, 0,
dev->cfg->frame_end_id);
mi_ctrl_mpyuv_enable(base);
mp_mi_ctrl_autoupdate_en(base);
return 0;
}
static void disable_mp(void __iomem *base)
{
mi_ctrl_mp_disable(base);
}
static struct rkisp_bridge_ops mp_ops = {
.config = config_mp,
.disable = disable_mp,
.is_stopped = mp_is_stream_stopped,
};
static struct rkisp_bridge_config mp_cfg = {
.frame_end_id = MI_MP_FRAME,
.reg = {
.y0_base = MI_MP_WR_Y_BASE,
.uv0_base = MI_MP_WR_CB_BASE,
.y1_base = MI_MP_WR_Y_BASE2,
.uv1_base = MI_MP_WR_CB_BASE2,
.g0_base = MI_GAIN_WR_BASE,
.g1_base = MI_GAIN_WR_BASE2,
.y0_base_shd = MI_MP_WR_Y_BASE_SHD,
.uv0_base_shd = MI_MP_WR_CB_BASE_SHD,
.g0_base_shd = MI_GAIN_WR_BASE_SHD,
},
};
static void free_bridge_buf(struct rkisp_bridge_device *dev)
{
struct rkisp_bridge_buf *buf;
struct rkisp_ispp_buf *dbufs;
int i, j;
if (dev->cur_buf) {
list_add_tail(&dev->cur_buf->list, &dev->list);
if (dev->cur_buf == dev->nxt_buf)
dev->nxt_buf = NULL;
dev->cur_buf = NULL;
}
if (dev->nxt_buf) {
list_add_tail(&dev->nxt_buf->list, &dev->list);
dev->nxt_buf = NULL;
}
while (!list_empty(&dev->list)) {
dbufs = list_first_entry(&dev->list,
struct rkisp_ispp_buf, list);
list_del(&dbufs->list);
}
for (i = 0; i < BRIDGE_BUF_MAX; i++) {
buf = &dev->bufs[i];
for (j = 0; j < GROUP_BUF_MAX; j++)
rkisp_free_buffer(dev->ispdev->dev, &buf->dummy[j]);
}
}
static int init_buf(struct rkisp_bridge_device *dev)
{
struct v4l2_subdev *sd = v4l2_get_subdev_hostdata(&dev->sd);
struct rkisp_bridge_buf *buf;
struct rkisp_dummy_buffer *dummy;
u32 width = dev->crop.width;
u32 height = dev->crop.height;
u32 offset = width * height;
u32 pic_size = 0, gain_size;
int i, j, ret = 0;
gain_size = ALIGN(width, 64) * ALIGN(height, 128) >> 4;
if (dev->work_mode & ISP_ISPP_FBC) {
width = ALIGN(width, 16);
height = ALIGN(height, 16);
offset = width * height >> 4;
pic_size = offset;
}
if (dev->work_mode & ISP_ISPP_422)
pic_size += width * height * 2;
else
pic_size += width * height * 3 >> 1;
dev->cfg->offset = offset;
for (i = 0; i < dev->buf_num; i++) {
buf = &dev->bufs[i];
for (j = 0; j < GROUP_BUF_MAX; j++) {
dummy = &buf->dummy[j];
dummy->is_need_dbuf = true;
dummy->size = !j ? pic_size : gain_size;
ret = rkisp_alloc_buffer(dev->ispdev->dev, dummy);
if (ret)
goto err;
buf->dbufs.dbuf[j] = dummy->dbuf;
}
list_add_tail(&buf->dbufs.list, &dev->list);
ret = v4l2_subdev_call(sd, video, s_rx_buffer, &buf->dbufs, NULL);
if (ret)
goto err;
}
return 0;
err:
free_bridge_buf(dev);
v4l2_err(&dev->sd, "%s fail:%d\n", __func__, ret);
return ret;
}
static int config_mode(struct rkisp_bridge_device *dev)
{
if (dev->work_mode == ISP_ISPP_INIT_FAIL) {
free_bridge_buf(dev);
return 0;
}
if (!dev->linked || !dev->ispdev->isp_inp) {
v4l2_err(&dev->sd,
"invalid: link:%d or isp input:0x%x\n",
dev->linked,
dev->ispdev->isp_inp);
return -EINVAL;
}
v4l2_dbg(1, rkisp_debug, &dev->sd,
"work mode:0x%x buf num:%d\n",
dev->work_mode, dev->buf_num);
if (dev->work_mode & ISP_ISPP_FBC) {
dev->ops = &mpfbc_ops;
dev->cfg = &mpfbc_cfg;
} else {
dev->ops = &mp_ops;
dev->cfg = &mp_cfg;
}
return init_buf(dev);
}
static void crop_on(struct rkisp_bridge_device *dev)
{
struct rkisp_device *ispdev = dev->ispdev;
void __iomem *base = ispdev->base_addr;
u32 src_w = ispdev->isp_sdev.out_crop.width;
u32 src_h = ispdev->isp_sdev.out_crop.height;
u32 dest_w = dev->crop.width;
u32 dest_h = dev->crop.height;
u32 left = dev->crop.left;
u32 top = dev->crop.top;
u32 ctrl;
if (src_w == dest_w && src_h == dest_h)
return;
writel(left, base + CIF_DUAL_CROP_M_H_OFFS);
writel(top, base + CIF_DUAL_CROP_M_V_OFFS);
writel(dest_w, base + CIF_DUAL_CROP_M_H_SIZE);
writel(dest_h, base + CIF_DUAL_CROP_M_V_SIZE);
ctrl = readl(base + CIF_DUAL_CROP_CTRL);
ctrl |= CIF_DUAL_CROP_MP_MODE_YUV | CIF_DUAL_CROP_CFG_UPD;
writel(ctrl, base + CIF_DUAL_CROP_CTRL);
}
static void crop_off(struct rkisp_bridge_device *dev)
{
struct rkisp_device *ispdev = dev->ispdev;
void __iomem *base = ispdev->base_addr;
u32 src_w = ispdev->isp_sdev.out_crop.width;
u32 src_h = ispdev->isp_sdev.out_crop.height;
u32 dest_w = dev->crop.width;
u32 dest_h = dev->crop.height;
u32 ctrl;
if (src_w == dest_w && src_h == dest_h)
return;
ctrl = readl(base + CIF_DUAL_CROP_CTRL);
ctrl &= ~(CIF_DUAL_CROP_MP_MODE_YUV |
CIF_DUAL_CROP_MP_MODE_RAW);
ctrl |= CIF_DUAL_CROP_GEN_CFG_UPD;
writel(ctrl, base + CIF_DUAL_CROP_CTRL);
}
static int bridge_start(struct rkisp_bridge_device *dev)
{
void __iomem *base = dev->ispdev->base_addr;
crop_on(dev);
config_gain(dev);
dev->ops->config(dev);
force_cfg_update(base);
if (!(dev->work_mode & ISP_ISPP_QUICK))
update_mi(dev);
dev->en = true;
return 0;
}
static int bridge_stop(struct rkisp_bridge_device *dev)
{
void __iomem *base = dev->ispdev->base_addr;
int ret;
dev->stopping = true;
dev->ops->disable(base);
hdr_stop_dmatx(dev->ispdev);
ret = wait_event_timeout(dev->done, !dev->en,
msecs_to_jiffies(1000));
if (!ret)
v4l2_warn(&dev->sd,
"%s timeout ret:%d\n", __func__, ret);
crop_off(dev);
isp_clear_bits(base + MI_IMSC, dev->cfg->frame_end_id);
dev->stopping = false;
dev->en = false;
/* make sure ispp last frame done */
if (dev->work_mode & ISP_ISPP_QUICK)
usleep_range(20000, 25000);
return 0;
}
static int bridge_start_stream(struct v4l2_subdev *sd)
{
struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd);
int ret;
if (WARN_ON(dev->en))
return -EBUSY;
if (dev->ispdev->isp_inp & INP_CSI ||
dev->ispdev->isp_inp & INP_DVP) {
/* Always update sensor info in case media topology changed */
ret = rkisp_update_sensor_info(dev->ispdev);
if (ret < 0) {
v4l2_err(sd, "update sensor info failed %d\n", ret);
goto free_buf;
}
}
/* enable clocks/power-domains */
ret = dev->ispdev->pipe.open(&dev->ispdev->pipe, &sd->entity, true);
if (ret < 0)
goto free_buf;
hdr_config_dmatx(dev->ispdev);
ret = bridge_start(dev);
if (ret)
goto close_pipe;
hdr_update_dmatx_buf(dev->ispdev);
/* start sub-devices */
ret = dev->ispdev->pipe.set_stream(&dev->ispdev->pipe, true);
if (ret < 0)
goto stop_bridge;
ret = media_pipeline_start(&sd->entity, &dev->ispdev->pipe.pipe);
if (ret < 0)
goto pipe_stream_off;
return 0;
pipe_stream_off:
dev->ispdev->pipe.set_stream(&dev->ispdev->pipe, false);
stop_bridge:
bridge_stop(dev);
close_pipe:
dev->ispdev->pipe.close(&dev->ispdev->pipe);
hdr_destroy_buf(dev->ispdev);
free_buf:
free_bridge_buf(dev);
v4l2_err(&dev->sd, "%s fail:%d\n", __func__, ret);
return ret;
}
static void bridge_destroy_buf(struct rkisp_bridge_device *dev)
{
free_bridge_buf(dev);
hdr_destroy_buf(dev->ispdev);
}
static int bridge_stop_stream(struct v4l2_subdev *sd)
{
struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd);
bridge_stop(dev);
media_pipeline_stop(&sd->entity);
dev->ispdev->pipe.set_stream(&dev->ispdev->pipe, false);
dev->ispdev->pipe.close(&dev->ispdev->pipe);
bridge_destroy_buf(dev);
return 0;
}
static int bridge_get_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd);
if (!fmt)
return -EINVAL;
/* get isp out format */
fmt->pad = RKISP_ISP_PAD_SOURCE_PATH;
fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
return v4l2_subdev_call(&dev->ispdev->isp_sdev.sd,
pad, get_fmt, NULL, fmt);
}
static int bridge_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd);
struct rkisp_isp_subdev *isp_sd = &dev->ispdev->isp_sdev;
u32 src_w = isp_sd->out_crop.width;
u32 src_h = isp_sd->out_crop.height;
struct v4l2_rect *crop;
if (!sel)
return -EINVAL;
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
crop = &sel->r;
crop->left = clamp_t(u32, crop->left, 0, src_w);
crop->top = clamp_t(u32, crop->top, 0, src_h);
crop->width = clamp_t(u32, crop->width,
CIF_ISP_OUTPUT_W_MIN, src_w - crop->left);
crop->height = clamp_t(u32, crop->height,
CIF_ISP_OUTPUT_H_MIN, src_h - crop->top);
dev->crop = *crop;
return 0;
}
static int bridge_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd);
struct rkisp_isp_subdev *isp_sd = &dev->ispdev->isp_sdev;
struct v4l2_rect *crop;
if (!sel)
return -EINVAL;
crop = &sel->r;
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
*crop = isp_sd->out_crop;
break;
case V4L2_SEL_TGT_CROP:
*crop = dev->crop;
break;
default:
return -EINVAL;
}
return 0;
}
static int bridge_s_rx_buffer(struct v4l2_subdev *sd,
void *buf, unsigned int *size)
{
struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd);
struct rkisp_ispp_buf *dbufs = buf;
unsigned long lock_flags = 0;
/* size isn't using now */
if (!dbufs)
return -EINVAL;
spin_lock_irqsave(&dev->buf_lock, lock_flags);
list_add_tail(&dbufs->list, &dev->list);
spin_unlock_irqrestore(&dev->buf_lock, lock_flags);
return 0;
}
static int bridge_s_stream(struct v4l2_subdev *sd, int on)
{
struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd);
int ret = 0;
v4l2_dbg(1, rkisp_debug, sd,
"%s %d\n", __func__, on);
if (on) {
atomic_inc(&dev->ispdev->cap_dev.refcnt);
ret = bridge_start_stream(sd);
} else if (dev->en) {
ret = bridge_stop_stream(sd);
}
if (!on)
atomic_dec(&dev->ispdev->cap_dev.refcnt);
return ret;
}
static int bridge_s_power(struct v4l2_subdev *sd, int on)
{
int ret = 0;
v4l2_dbg(1, rkisp_debug, sd,
"%s %d\n", __func__, on);
if (on)
ret = v4l2_pipeline_pm_use(&sd->entity, 1);
else
ret = v4l2_pipeline_pm_use(&sd->entity, 0);
return ret;
}
static long bridge_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd);
struct rkisp_ispp_mode *mode;
long ret = 0;
switch (cmd) {
case RKISP_ISPP_CMD_SET_MODE:
mode = arg;
dev->work_mode = mode->work_mode;
dev->buf_num = mode->buf_num;
ret = config_mode(dev);
break;
default:
ret = -ENOIOCTLCMD;
}
return ret;
}
static const struct v4l2_subdev_pad_ops bridge_pad_ops = {
.set_fmt = bridge_get_set_fmt,
.get_fmt = bridge_get_set_fmt,
.get_selection = bridge_get_selection,
.set_selection = bridge_set_selection,
};
static const struct v4l2_subdev_video_ops bridge_video_ops = {
.s_rx_buffer = bridge_s_rx_buffer,
.s_stream = bridge_s_stream,
};
static const struct v4l2_subdev_core_ops bridge_core_ops = {
.s_power = bridge_s_power,
.ioctl = bridge_ioctl,
};
static struct v4l2_subdev_ops bridge_v4l2_ops = {
.core = &bridge_core_ops,
.video = &bridge_video_ops,
.pad = &bridge_pad_ops,
};
void rkisp_bridge_isr(u32 *mis_val, struct rkisp_device *dev)
{
struct rkisp_bridge_device *bridge = &dev->br_dev;
void __iomem *base = dev->base_addr;
if (!bridge->en || !bridge->cfg ||
(bridge->cfg &&
!(*mis_val & bridge->cfg->frame_end_id)))
return;
*mis_val &= ~bridge->cfg->frame_end_id;
writel(bridge->cfg->frame_end_id, base + CIF_MI_ICR);
if (bridge->stopping) {
if (bridge->ops->is_stopped(base)) {
bridge->en = false;
bridge->stopping = false;
wake_up(&bridge->done);
}
} else if (!(bridge->work_mode & ISP_ISPP_QUICK)) {
frame_end(bridge);
}
}
int rkisp_register_bridge_subdev(struct rkisp_device *dev,
struct v4l2_device *v4l2_dev)
{
struct rkisp_bridge_device *bridge = &dev->br_dev;
struct v4l2_subdev *sd;
struct media_entity *source, *sink;
int ret;
memset(bridge, 0, sizeof(*bridge));
if (dev->isp_ver != ISP_V20)
return 0;
bridge->ispdev = dev;
sd = &bridge->sd;
v4l2_subdev_init(sd, &bridge_v4l2_ops);
//sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->entity.obj_type = 0;
snprintf(sd->name, sizeof(sd->name), BRIDGE_DEV_NAME);
bridge->pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_pads_init(&sd->entity, 1, &bridge->pad);
if (ret < 0)
return ret;
sd->owner = THIS_MODULE;
v4l2_set_subdevdata(sd, bridge);
sd->grp_id = GRP_ID_ISP_BRIDGE;
ret = v4l2_device_register_subdev(v4l2_dev, sd);
if (ret < 0) {
v4l2_err(sd, "Failed to register subdev\n");
goto free_media;
}
bridge->crop = dev->isp_sdev.out_crop;
/* bridge links */
bridge->linked = true;
source = &dev->isp_sdev.sd.entity;
sink = &sd->entity;
ret = media_create_pad_link(source, RKISP_ISP_PAD_SOURCE_PATH,
sink, 0, bridge->linked);
init_waitqueue_head(&bridge->done);
spin_lock_init(&bridge->buf_lock);
INIT_LIST_HEAD(&bridge->list);
return ret;
free_media:
media_entity_cleanup(&sd->entity);
return ret;
}
void rkisp_unregister_bridge_subdev(struct rkisp_device *dev)
{
struct v4l2_subdev *sd = &dev->br_dev.sd;
if (dev->isp_ver != ISP_V20)
return;
v4l2_device_unregister_subdev(sd);
media_entity_cleanup(&sd->entity);
}
void rkisp_get_bridge_sd(struct platform_device *dev,
struct v4l2_subdev **sd)
{
struct rkisp_device *isp_dev = platform_get_drvdata(dev);
if (isp_dev)
*sd = &isp_dev->br_dev.sd;
else
*sd = NULL;
}

View File

@@ -0,0 +1,70 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
#ifndef _RKISP_BRIDGE_H
#define _RKISP_BRIDGE_H
#include "linux/platform_device.h"
#include "isp_ispp.h"
#define BRIDGE_DEV_NAME DRIVER_NAME "-bridge-ispp"
#define BRIDGE_BUF_MAX (RKISP_ISPP_BUF_MAX + 1)
struct rkisp_bridge_device;
struct rkisp_bridge_ops {
int (*config)(struct rkisp_bridge_device *dev);
void (*disable)(void __iomem *base);
bool (*is_stopped)(void __iomem *base);
};
struct rkisp_bridge_config {
const int frame_end_id;
u32 offset;
struct {
u32 y0_base;
u32 uv0_base;
u32 y1_base;
u32 uv1_base;
u32 g0_base;
u32 g1_base;
u32 y0_base_shd;
u32 uv0_base_shd;
u32 g0_base_shd;
} reg;
};
struct rkisp_bridge_buf {
struct rkisp_ispp_buf dbufs;
struct rkisp_dummy_buffer dummy[GROUP_BUF_MAX];
};
struct rkisp_bridge_device {
struct rkisp_device *ispdev;
struct v4l2_subdev sd;
struct v4l2_rect crop;
struct media_pad pad;
wait_queue_head_t done;
spinlock_t buf_lock;
struct list_head list;
struct rkisp_bridge_buf bufs[BRIDGE_BUF_MAX];
struct rkisp_ispp_buf *cur_buf;
struct rkisp_ispp_buf *nxt_buf;
struct rkisp_bridge_ops *ops;
struct rkisp_bridge_config *cfg;
u8 work_mode;
u8 buf_num;
bool pingpong;
bool stopping;
bool linked;
bool en;
};
int rkisp_register_bridge_subdev(struct rkisp_device *dev,
struct v4l2_device *v4l2_dev);
void rkisp_unregister_bridge_subdev(struct rkisp_device *dev);
void rkisp_bridge_isr(u32 *mis_val, struct rkisp_device *dev);
void rkisp_get_bridge_sd(struct platform_device *dev,
struct v4l2_subdev **sd);
#endif

View File

@@ -782,7 +782,7 @@ static int rkisp_config_rsz(struct rkisp_stream *stream, bool async)
u32 xsubs_out = 1, ysubs_out = 1;
if (input_isp_fmt->fmt_type == FMT_BAYER ||
dev->mpfbc_dev.en)
dev->br_dev.en)
goto disable;
/* set input and output sizes for scale calculation */
@@ -1901,16 +1901,14 @@ static void rkisp_stream_stop(struct rkisp_stream *stream)
ret = wait_event_timeout(stream->done,
!stream->streaming,
msecs_to_jiffies(1000));
if (!ret) {
v4l2_warn(v4l2_dev, "waiting on event return error %d\n", ret);
stream->stopping = false;
stream->streaming = false;
}
} else {
stream->stopping = false;
stream->streaming = false;
if (!ret)
v4l2_warn(v4l2_dev, "%s id:%d timeout\n",
__func__, stream->id);
}
stream->stopping = false;
stream->streaming = false;
if (stream->id == RKISP_STREAM_MP ||
stream->id == RKISP_STREAM_SP) {
disable_dcrop(stream, true);
@@ -1979,7 +1977,7 @@ static int rkisp_start(struct rkisp_stream *stream)
* also required because the sencond FE maybe corrupt especially
* when run at 120fps.
*/
if (is_update && !dev->mpfbc_dev.en) {
if (is_update && !dev->br_dev.en) {
rkisp_stats_first_ddr_config(&dev->stats_vdev);
force_cfg_update(base);
mi_frame_end(stream);
@@ -2563,7 +2561,8 @@ void rkisp_set_stream_def_fmt(struct rkisp_device *dev, u32 id,
struct v4l2_pix_format_mplane pixm;
memset(&pixm, 0, sizeof(pixm));
pixm.pixelformat = pixelformat;
if (pixelformat)
pixm.pixelformat = pixelformat;
pixm.width = width;
pixm.height = height;
rkisp_set_fmt(stream, &pixm, false);
@@ -2937,7 +2936,7 @@ static int rkisp_stream_init(struct rkisp_device *dev, u32 id)
init_waitqueue_head(&stream->done);
spin_lock_init(&stream->vbq_lock);
/* isp2 disable MP/SP, enable MPFBC default */
/* isp2 disable MP/SP, enable BRIDGE default */
if ((id == RKISP_STREAM_SP || id == RKISP_STREAM_MP) &&
dev->isp_ver == ISP_V20)
stream->linked = false;
@@ -3111,8 +3110,8 @@ void rkisp_mi_isr(u32 mis_val, struct rkisp_device *dev)
v4l2_dbg(3, rkisp_debug, &dev->v4l2_dev,
"mi isr:0x%x\n", mis_val);
if (mis_val & MI_MPFBC_FRAME)
rkisp_mpfbc_isr(mis_val, dev);
rkisp_bridge_isr(&mis_val, dev);
if (mis_val & CIF_MI_DMA_READY)
rkisp_dmarx_isr(mis_val, dev);

View File

@@ -41,6 +41,7 @@
#include <media/media-entity.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-v4l2.h>
#include <media/v4l2-mc.h>
@@ -103,9 +104,13 @@ struct rkisp_buffer {
struct rkisp_dummy_buffer {
struct list_head queue;
void *vaddr;
struct dma_buf *dbuf;
dma_addr_t dma_addr;
void *mem_priv;
void *vaddr;
u32 size;
bool is_need_vaddr;
bool is_need_dbuf;
};
extern int rkisp_debug;
@@ -136,6 +141,9 @@ static inline struct vb2_queue *to_vb2_queue(struct file *file)
static inline int rkisp_alloc_buffer(struct device *dev,
struct rkisp_dummy_buffer *buf)
{
const struct vb2_mem_ops *ops = &vb2_dma_contig_memops;
unsigned long attrs = buf->is_need_vaddr ? 0 : DMA_ATTR_NO_KERNEL_MAPPING;
void *mem_priv;
int ret = 0;
if (!buf->size) {
@@ -143,13 +151,19 @@ static inline int rkisp_alloc_buffer(struct device *dev,
goto err;
}
buf->vaddr = dma_alloc_coherent(dev, buf->size,
&buf->dma_addr, GFP_KERNEL);
if (!buf->vaddr) {
mem_priv = ops->alloc(dev, attrs, buf->size,
DMA_BIDIRECTIONAL, GFP_KERNEL);
if (IS_ERR_OR_NULL(mem_priv)) {
ret = -ENOMEM;
goto err;
}
buf->mem_priv = mem_priv;
buf->dma_addr = *((dma_addr_t *)ops->cookie(mem_priv));
if (!attrs)
buf->vaddr = ops->vaddr(mem_priv);
if (buf->is_need_dbuf)
buf->dbuf = ops->get_dmabuf(mem_priv, O_RDWR);
if (rkisp_debug)
dev_info(dev, "%s buf:0x%x~0x%x size:%d\n", __func__,
(u32)buf->dma_addr, (u32)buf->dma_addr + buf->size, buf->size);
@@ -163,14 +177,21 @@ err:
static inline void rkisp_free_buffer(struct device *dev,
struct rkisp_dummy_buffer *buf)
{
if (buf && buf->vaddr && buf->size) {
const struct vb2_mem_ops *ops = &vb2_dma_contig_memops;
if (buf && buf->mem_priv) {
if (rkisp_debug)
dev_info(dev, "%s buf:0x%x~0x%x\n", __func__,
(u32)buf->dma_addr, (u32)buf->dma_addr + buf->size);
dma_free_coherent(dev, buf->size,
buf->vaddr, buf->dma_addr);
if (buf->dbuf)
dma_buf_put(buf->dbuf);
ops->put(buf->mem_priv);
buf->size = 0;
buf->dbuf = NULL;
buf->vaddr = NULL;
buf->mem_priv = NULL;
buf->is_need_dbuf = false;
buf->is_need_vaddr = false;
}
}

View File

@@ -509,13 +509,13 @@ static int rkisp_register_platform_subdevs(struct rkisp_device *dev)
if (ret < 0)
goto err_unreg_isp_subdev;
ret = rkisp_register_mpfbc_subdev(dev, &dev->v4l2_dev);
ret = rkisp_register_bridge_subdev(dev, &dev->v4l2_dev);
if (ret < 0)
goto err_unreg_csi_subdev;
ret = rkisp_register_stream_vdevs(dev);
if (ret < 0)
goto err_unreg_mpfbc_subdev;
goto err_unreg_bridge_subdev;
ret = rkisp_register_dmarx_vdev(dev);
if (ret < 0)
@@ -555,8 +555,8 @@ err_unreg_dmarx_vdev:
rkisp_unregister_dmarx_vdev(dev);
err_unreg_stream_vdev:
rkisp_unregister_stream_vdevs(dev);
err_unreg_mpfbc_subdev:
rkisp_unregister_mpfbc_subdev(dev);
err_unreg_bridge_subdev:
rkisp_unregister_bridge_subdev(dev);
err_unreg_csi_subdev:
rkisp_unregister_csi_subdev(dev);
err_unreg_isp_subdev:
@@ -1108,7 +1108,7 @@ static int rkisp_plat_remove(struct platform_device *pdev)
rkisp_unregister_params_vdev(&isp_dev->params_vdev);
rkisp_unregister_stats_vdev(&isp_dev->stats_vdev);
rkisp_unregister_stream_vdevs(isp_dev);
rkisp_unregister_mpfbc_subdev(isp_dev);
rkisp_unregister_bridge_subdev(isp_dev);
rkisp_unregister_csi_subdev(isp_dev);
rkisp_unregister_isp_subdev(isp_dev);
media_device_cleanup(&isp_dev->media_dev);

View File

@@ -38,7 +38,7 @@
#include "capture.h"
#include "csi.h"
#include "dmarx.h"
#include "mpfbc.h"
#include "bridge.h"
#include "rkisp.h"
#include "isp_params.h"
#include "isp_stats.h"
@@ -69,7 +69,7 @@
#define GRP_ID_ISP_MP BIT(3)
#define GRP_ID_ISP_SP BIT(4)
#define GRP_ID_ISP_DMARX BIT(5)
#define GRP_ID_ISP_MPFBC BIT(6)
#define GRP_ID_ISP_BRIDGE BIT(6)
#define GRP_ID_CSI BIT(7)
#define RKISP_MAX_BUS_CLK 8
@@ -171,7 +171,7 @@ struct rkisp_hdr {
* @params_vdev: ISP input parameters device
* @dmarx_dev: image input device
* @csi_dev: mipi csi device
* @mpfbc_dev: mpfbc output device
* @br_dev: bridge of isp and ispp device
*/
struct rkisp_device {
struct list_head list;
@@ -195,7 +195,7 @@ struct rkisp_device {
struct rkisp_isp_params_vdev params_vdev;
struct rkisp_dmarx_device dmarx_dev;
struct rkisp_csi_device csi_dev;
struct rkisp_mpfbc_device mpfbc_dev;
struct rkisp_bridge_device br_dev;
struct rkisp_luma_vdev luma_vdev;
struct rkisp_pipeline pipe;
struct iommu_domain *domain;

View File

@@ -7,16 +7,44 @@
#include <linux/platform_device.h>
#include <media/v4l2-subdev.h>
#define RKISP_ISPP_BUF_MAX 4
#define RKISP_ISPP_CMD_SET_MODE \
_IOW('V', BASE_VIDIOC_PRIVATE + 0, struct rkisp_ispp_mode)
enum rkisp_ispp_buf_group {
GROUP_BUF_PIC = 0,
GROUP_BUF_GAIN,
GROUP_BUF_MAX,
};
enum rkisp_ispp_work_mode {
ISP_ISPP_FBC = BIT(0),
ISP_ISPP_422 = BIT(1),
ISP_ISPP_QUICK = BIT(2),
ISP_ISPP_INIT_FAIL = BIT(7),
};
struct rkisp_ispp_mode {
u8 work_mode;
u8 buf_num;
};
struct rkisp_ispp_buf {
struct list_head list;
struct dma_buf *dbuf[GROUP_BUF_MAX];
u32 frame_id;
};
#if IS_BUILTIN(CONFIG_VIDEO_ROCKCHIP_ISP) && IS_BUILTIN(CONFIG_VIDEO_ROCKCHIP_ISPP)
int __init rkispp_plat_drv_init(void);
#endif
#if defined(CONFIG_VIDEO_ROCKCHIP_ISP)
void rkisp_get_mpfbc_sd(struct platform_device *dev,
struct v4l2_subdev **sd);
void rkisp_get_bridge_sd(struct platform_device *dev,
struct v4l2_subdev **sd);
#else
static inline void rkisp_get_mpfbc_sd(struct platform_device *dev,
struct v4l2_subdev **sd)
static inline void rkisp_get_bridge_sd(struct platform_device *dev,
struct v4l2_subdev **sd)
{
*sd = NULL;
}

View File

@@ -4183,6 +4183,7 @@ int rkisp_init_params_vdev_v2x(struct rkisp_isp_params_vdev *params_vdev)
priv_val->buf_3dlut_idx = 0;
for (i = 0; i < RKISP_PARAM_3DLUT_BUF_NUM; i++) {
priv_val->buf_3dlut[i].is_need_vaddr = true;
priv_val->buf_3dlut[i].size = RKISP_PARAM_3DLUT_BUF_SIZE;
ret = rkisp_alloc_buffer(dev, &priv_val->buf_3dlut[i]);
if (ret) {
@@ -4193,6 +4194,7 @@ int rkisp_init_params_vdev_v2x(struct rkisp_isp_params_vdev *params_vdev)
priv_val->buf_lsclut_idx = 0;
for (i = 0; i < RKISP_PARAM_LSC_LUT_BUF_NUM; i++) {
priv_val->buf_lsclut[i].is_need_vaddr = true;
priv_val->buf_lsclut[i].size = RKISP_PARAM_LSC_LUT_BUF_SIZE;
ret = rkisp_alloc_buffer(dev, &priv_val->buf_lsclut[i]);
if (ret) {
@@ -4203,6 +4205,7 @@ int rkisp_init_params_vdev_v2x(struct rkisp_isp_params_vdev *params_vdev)
priv_val->buf_ldch_idx = 0;
for (i = 0; i < RKISP_PARAM_LDCH_BUF_NUM; i++) {
priv_val->buf_ldch[i].is_need_vaddr = true;
priv_val->buf_ldch[i].size = ISP2X_LDCH_MESH_XY_NUM * sizeof(u16);
ret = rkisp_alloc_buffer(dev, &priv_val->buf_ldch[i]);
if (ret) {

View File

@@ -1508,6 +1508,7 @@ void rkisp_init_stats_vdev_v2x(struct rkisp_isp_stats_vdev *stats_vdev)
stats_vdev->rd_buf_idx = 0;
stats_vdev->wr_buf_idx = 0;
for (i = 0; i < RKISP_STATS_DDR_BUF_NUM; i++) {
stats_vdev->stats_buf[i].is_need_vaddr = true;
stats_vdev->stats_buf[i].size = RKISP_RD_STATS_BUF_SIZE;
rkisp_alloc_buffer(stats_vdev->dev->dev, &stats_vdev->stats_buf[i]);
}

View File

@@ -1,505 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <media/v4l2-common.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf2-dma-contig.h>
#include <linux/dma-iommu.h>
#include <linux/rk-camera-module.h>
#include "dev.h"
#include "regs.h"
static int mpfbc_get_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd);
struct rkisp_device *dev = mpfbc_dev->ispdev;
if (!fmt)
return -EINVAL;
/* get isp out format */
fmt->pad = RKISP_ISP_PAD_SOURCE_PATH;
fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
return v4l2_subdev_call(&dev->isp_sdev.sd, pad, get_fmt, NULL, fmt);
}
static int mpfbc_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd);
struct rkisp_isp_subdev *isp_sd = &mpfbc_dev->ispdev->isp_sdev;
u32 src_w = isp_sd->out_crop.width;
u32 src_h = isp_sd->out_crop.height;
struct v4l2_rect *crop;
if (!sel)
return -EINVAL;
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
crop = &sel->r;
crop->left = clamp_t(u32, crop->left, 0, src_w);
crop->top = clamp_t(u32, crop->top, 0, src_h);
crop->width = clamp_t(u32, crop->width,
CIF_ISP_OUTPUT_W_MIN, src_w - crop->left);
crop->height = clamp_t(u32, crop->height,
CIF_ISP_OUTPUT_H_MIN, src_h - crop->top);
mpfbc_dev->crop = *crop;
return 0;
}
static int mpfbc_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd);
struct rkisp_isp_subdev *isp_sd = &mpfbc_dev->ispdev->isp_sdev;
struct v4l2_rect *crop;
if (!sel)
return -EINVAL;
crop = &sel->r;
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
*crop = isp_sd->out_crop;
break;
case V4L2_SEL_TGT_CROP:
*crop = mpfbc_dev->crop;
break;
default:
return -EINVAL;
}
return 0;
}
static void mpfbc_crop_on(struct rkisp_mpfbc_device *mpfbc_dev)
{
struct rkisp_device *dev = mpfbc_dev->ispdev;
void __iomem *base = dev->base_addr;
u32 src_w = dev->isp_sdev.out_crop.width;
u32 src_h = dev->isp_sdev.out_crop.height;
u32 dest_w = mpfbc_dev->crop.width;
u32 dest_h = mpfbc_dev->crop.height;
u32 left = mpfbc_dev->crop.left;
u32 top = mpfbc_dev->crop.top;
u32 ctrl;
if (src_w == dest_w && src_h == dest_h)
return;
writel(left, base + CIF_DUAL_CROP_M_H_OFFS);
writel(top, base + CIF_DUAL_CROP_M_V_OFFS);
writel(dest_w, base + CIF_DUAL_CROP_M_H_SIZE);
writel(dest_h, base + CIF_DUAL_CROP_M_V_SIZE);
ctrl = readl(base + CIF_DUAL_CROP_CTRL);
ctrl |= CIF_DUAL_CROP_MP_MODE_YUV | CIF_DUAL_CROP_CFG_UPD;
writel(ctrl, base + CIF_DUAL_CROP_CTRL);
}
static void mpfbc_crop_off(struct rkisp_mpfbc_device *mpfbc_dev)
{
struct rkisp_device *dev = mpfbc_dev->ispdev;
void __iomem *base = dev->base_addr;
u32 src_w = dev->isp_sdev.out_crop.width;
u32 src_h = dev->isp_sdev.out_crop.height;
u32 dest_w = mpfbc_dev->crop.width;
u32 dest_h = mpfbc_dev->crop.height;
u32 ctrl;
if (src_w == dest_w && src_h == dest_h)
return;
ctrl = readl(base + CIF_DUAL_CROP_CTRL);
ctrl &= ~(CIF_DUAL_CROP_MP_MODE_YUV |
CIF_DUAL_CROP_MP_MODE_RAW);
ctrl |= CIF_DUAL_CROP_GEN_CFG_UPD;
writel(ctrl, base + CIF_DUAL_CROP_CTRL);
}
static void free_dma_buf(struct rkisp_dma_buf *buf)
{
const struct vb2_mem_ops *ops = &vb2_dma_contig_memops;
if (!buf)
return;
ops->unmap_dmabuf(buf->mem_priv);
ops->detach_dmabuf(buf->mem_priv);
dma_buf_put(buf->dbuf);
kfree(buf);
}
static void mpfbc_free_dma_buf(struct rkisp_mpfbc_device *dev)
{
free_dma_buf(dev->pic_cur);
dev->pic_cur = NULL;
free_dma_buf(dev->pic_nxt);
dev->pic_nxt = NULL;
free_dma_buf(dev->gain_cur);
dev->gain_cur = NULL;
free_dma_buf(dev->gain_nxt);
dev->gain_nxt = NULL;
}
static int mpfbc_s_rx_buffer(struct v4l2_subdev *sd,
void *dbuf, unsigned int *size)
{
struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd);
struct rkisp_device *dev = mpfbc_dev->ispdev;
void __iomem *base = dev->base_addr;
const struct vb2_mem_ops *ops = &vb2_dma_contig_memops;
struct rkisp_dma_buf *buf;
dma_addr_t dma_addr;
u32 w = ALIGN(mpfbc_dev->crop.width, 16);
u32 h = ALIGN(mpfbc_dev->crop.height, 16);
u32 sizes = (w * h >> 4) + w * h * 2;
u32 w_tmp;
int ret = 0;
if (!dbuf || !size)
return -EINVAL;
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto err;
}
buf->dbuf = dbuf;
buf->mem_priv = ops->attach_dmabuf(dev->dev, dbuf,
*size, DMA_BIDIRECTIONAL);
if (IS_ERR(buf->mem_priv)) {
ret = PTR_ERR(buf->mem_priv);
goto err;
}
ret = ops->map_dmabuf(buf->mem_priv);
if (ret) {
ops->detach_dmabuf(buf->mem_priv);
goto err;
}
dma_addr = *((dma_addr_t *)ops->cookie(buf->mem_priv));
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
"%s buf:0x%x size:%d\n",
__func__, (u32)dma_addr, *size);
/* picture or gain buffer */
if (*size == sizes) {
if (mpfbc_dev->pic_cur) {
mpfbc_dev->pic_nxt = buf;
writel(dma_addr, base + ISP_MPFBC_HEAD_PTR2);
writel(dma_addr + (w * h >> 4),
base + ISP_MPFBC_PAYL_PTR2);
mpfbc_dev->pingpong = true;
} else {
mpfbc_dev->pic_cur = buf;
writel(dma_addr, base + ISP_MPFBC_HEAD_PTR);
writel(dma_addr + (w * h >> 4),
base + ISP_MPFBC_PAYL_PTR);
mpfbc_dev->pingpong = false;
}
} else {
if (mpfbc_dev->gain_cur) {
mpfbc_dev->gain_nxt = buf;
writel(dma_addr, base + MI_GAIN_WR_BASE2);
mi_wr_ctrl2(base, SW_GAIN_WR_PINGPONG);
} else {
mpfbc_dev->gain_cur = buf;
writel(dma_addr, base + MI_GAIN_WR_BASE);
isp_clear_bits(base + MI_WR_CTRL2,
SW_GAIN_WR_PINGPONG);
}
writel(*size, base + MI_GAIN_WR_SIZE);
w_tmp = (mpfbc_dev->crop.width + 3) / 4;
w_tmp = ALIGN(w_tmp, 16);
writel(w_tmp, base + MI_GAIN_WR_LENGTH);
mi_wr_ctrl2(base, SW_GAIN_WR_AUTOUPD);
}
return 0;
err:
kfree(buf);
dma_buf_put(dbuf);
mpfbc_free_dma_buf(mpfbc_dev);
return ret;
}
static int mpfbc_start(struct rkisp_mpfbc_device *mpfbc_dev)
{
struct rkisp_device *dev = mpfbc_dev->ispdev;
void __iomem *base = dev->base_addr;
u32 h = ALIGN(mpfbc_dev->crop.height, 16);
mpfbc_crop_on(mpfbc_dev);
writel(mpfbc_dev->pingpong << 4 | SW_MPFBC_YUV_MODE(1) |
SW_MPFBC_MAINISP_MODE | SW_MPFBC_EN,
base + ISP_MPFBC_BASE);
writel(0, base + ISP_MPFBC_VIR_WIDTH);
writel(h, base + ISP_MPFBC_VIR_HEIGHT);
isp_set_bits(base + CTRL_SWS_CFG, 0, SW_ISP2PP_PIPE_EN);
isp_set_bits(base + MI_IMSC, 0, MI_MPFBC_FRAME);
isp_set_bits(base + MI_WR_CTRL, 0, CIF_MI_CTRL_INIT_BASE_EN);
mp_set_data_path(base);
force_cfg_update(base);
mpfbc_dev->en = true;
return 0;
}
static int mpfbc_stop(struct rkisp_mpfbc_device *mpfbc_dev)
{
struct rkisp_device *dev = mpfbc_dev->ispdev;
void __iomem *base = dev->base_addr;
int ret;
mpfbc_dev->stopping = true;
isp_clear_bits(base + ISP_MPFBC_BASE, SW_MPFBC_EN);
hdr_stop_dmatx(dev);
ret = wait_event_timeout(mpfbc_dev->done,
!mpfbc_dev->en,
msecs_to_jiffies(1000));
if (!ret)
v4l2_warn(&mpfbc_dev->sd,
"waiting on event return error %d\n", ret);
mpfbc_crop_off(mpfbc_dev);
mpfbc_dev->stopping = false;
isp_clear_bits(base + MI_IMSC, MI_MPFBC_FRAME);
mpfbc_dev->en = false;
return 0;
}
static int mpfbc_start_stream(struct v4l2_subdev *sd)
{
struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd);
struct rkisp_device *dev = mpfbc_dev->ispdev;
int ret;
if (!mpfbc_dev->linked || !dev->isp_inp) {
v4l2_err(&dev->v4l2_dev,
"mpfbc no linked or isp inval input\n");
return -EINVAL;
}
if (WARN_ON(mpfbc_dev->en))
return -EBUSY;
if (dev->isp_inp & INP_CSI ||
dev->isp_inp & INP_DVP) {
/* Always update sensor info in case media topology changed */
ret = rkisp_update_sensor_info(dev);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev,
"update sensor info failed %d\n",
ret);
return -EBUSY;
}
}
/* enable clocks/power-domains */
ret = dev->pipe.open(&dev->pipe, &sd->entity, true);
if (ret < 0)
return ret;
hdr_config_dmatx(dev);
ret = mpfbc_start(mpfbc_dev);
if (ret < 0)
goto close_pipe;
hdr_update_dmatx_buf(dev);
/* start sub-devices */
ret = dev->pipe.set_stream(&dev->pipe, true);
if (ret < 0)
goto stop_mpfbc;
ret = media_pipeline_start(&sd->entity, &dev->pipe.pipe);
if (ret < 0)
goto pipe_stream_off;
return 0;
pipe_stream_off:
dev->pipe.set_stream(&dev->pipe, false);
stop_mpfbc:
mpfbc_stop(mpfbc_dev);
hdr_destroy_buf(dev);
close_pipe:
dev->pipe.close(&dev->pipe);
return ret;
}
static void mpfbc_destroy_buf(struct rkisp_device *dev)
{
mpfbc_free_dma_buf(&dev->mpfbc_dev);
hdr_destroy_buf(dev);
}
static int mpfbc_stop_stream(struct v4l2_subdev *sd)
{
struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd);
struct rkisp_device *dev = mpfbc_dev->ispdev;
mpfbc_stop(mpfbc_dev);
media_pipeline_stop(&sd->entity);
dev->pipe.set_stream(&dev->pipe, false);
dev->pipe.close(&dev->pipe);
mpfbc_destroy_buf(dev);
return 0;
}
static int mpfbc_s_stream(struct v4l2_subdev *sd, int on)
{
struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd);
struct rkisp_device *dev = mpfbc_dev->ispdev;
int ret = 0;
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
"%s %d\n", __func__, on);
if (on) {
atomic_inc(&dev->cap_dev.refcnt);
ret = mpfbc_start_stream(sd);
} else if (mpfbc_dev->en) {
ret = mpfbc_stop_stream(sd);
}
if (!on)
atomic_dec(&dev->cap_dev.refcnt);
return ret;
}
static int mpfbc_s_power(struct v4l2_subdev *sd, int on)
{
struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd);
struct rkisp_device *dev = mpfbc_dev->ispdev;
int ret = 0;
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
"%s %d\n", __func__, on);
if (on)
ret = v4l2_pipeline_pm_use(&sd->entity, 1);
else
ret = v4l2_pipeline_pm_use(&sd->entity, 0);
return ret;
}
void rkisp_mpfbc_isr(u32 mis_val, struct rkisp_device *dev)
{
struct rkisp_mpfbc_device *mpfbc_dev = &dev->mpfbc_dev;
void __iomem *base = dev->base_addr;
writel(MI_MPFBC_FRAME, base + CIF_MI_ICR);
if (mpfbc_dev->stopping) {
if (is_mpfbc_stopped(base)) {
mpfbc_dev->en = false;
mpfbc_dev->stopping = false;
wake_up(&mpfbc_dev->done);
}
}
}
static const struct v4l2_subdev_pad_ops mpfbc_pad_ops = {
.set_fmt = mpfbc_get_set_fmt,
.get_fmt = mpfbc_get_set_fmt,
.get_selection = mpfbc_get_selection,
.set_selection = mpfbc_set_selection,
};
static const struct v4l2_subdev_video_ops mpfbc_video_ops = {
.s_rx_buffer = mpfbc_s_rx_buffer,
.s_stream = mpfbc_s_stream,
};
static const struct v4l2_subdev_core_ops mpfbc_core_ops = {
.s_power = mpfbc_s_power,
};
static struct v4l2_subdev_ops mpfbc_v4l2_ops = {
.core = &mpfbc_core_ops,
.video = &mpfbc_video_ops,
.pad = &mpfbc_pad_ops,
};
int rkisp_register_mpfbc_subdev(struct rkisp_device *dev,
struct v4l2_device *v4l2_dev)
{
struct rkisp_mpfbc_device *mpfbc_dev = &dev->mpfbc_dev;
struct v4l2_subdev *sd;
struct media_entity *source, *sink;
int ret;
memset(mpfbc_dev, 0, sizeof(*mpfbc_dev));
if (dev->isp_ver != ISP_V20)
return 0;
mpfbc_dev->ispdev = dev;
sd = &mpfbc_dev->sd;
v4l2_subdev_init(sd, &mpfbc_v4l2_ops);
//sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->entity.obj_type = 0;
snprintf(sd->name, sizeof(sd->name), MPFBC_DEV_NAME);
mpfbc_dev->pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_pads_init(&sd->entity, 1, &mpfbc_dev->pad);
if (ret < 0)
return ret;
sd->owner = THIS_MODULE;
v4l2_set_subdevdata(sd, mpfbc_dev);
sd->grp_id = GRP_ID_ISP_MPFBC;
ret = v4l2_device_register_subdev(v4l2_dev, sd);
if (ret < 0) {
v4l2_err(v4l2_dev, "Failed to register mpfbc subdev\n");
goto free_media;
}
mpfbc_dev->crop = dev->isp_sdev.out_crop;
/* mpfbc links */
mpfbc_dev->linked = true;
source = &dev->isp_sdev.sd.entity;
sink = &sd->entity;
ret = media_create_pad_link(source, RKISP_ISP_PAD_SOURCE_PATH,
sink, 0, mpfbc_dev->linked);
init_waitqueue_head(&mpfbc_dev->done);
return ret;
free_media:
media_entity_cleanup(&sd->entity);
return ret;
}
void rkisp_unregister_mpfbc_subdev(struct rkisp_device *dev)
{
struct v4l2_subdev *sd = &dev->mpfbc_dev.sd;
if (dev->isp_ver != ISP_V20)
return;
v4l2_device_unregister_subdev(sd);
media_entity_cleanup(&sd->entity);
}
void rkisp_get_mpfbc_sd(struct platform_device *dev,
struct v4l2_subdev **sd)
{
struct rkisp_device *isp_dev = platform_get_drvdata(dev);
if (isp_dev)
*sd = &isp_dev->mpfbc_dev.sd;
else
*sd = NULL;
}

View File

@@ -1,40 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
#ifndef _RKISP_mpfbc_H
#define _RKISP_mpfbc_H
#include "linux/platform_device.h"
#define MPFBC_DEV_NAME DRIVER_NAME "-mpfbc-subdev"
struct rkisp_mpfbc_device;
struct rkisp_dma_buf {
struct dma_buf *dbuf;
void *mem_priv;
};
struct rkisp_mpfbc_device {
struct rkisp_device *ispdev;
struct v4l2_subdev sd;
struct v4l2_rect crop;
struct media_pad pad;
wait_queue_head_t done;
struct rkisp_dma_buf *pic_cur;
struct rkisp_dma_buf *pic_nxt;
struct rkisp_dma_buf *gain_cur;
struct rkisp_dma_buf *gain_nxt;
u8 pingpong;
u8 stopping;
u8 en;
bool linked;
};
int rkisp_register_mpfbc_subdev(struct rkisp_device *dev,
struct v4l2_device *v4l2_dev);
void rkisp_unregister_mpfbc_subdev(struct rkisp_device *dev);
void rkisp_mpfbc_isr(u32 mis_val, struct rkisp_device *dev);
void rkisp_get_mpfbc_sd(struct platform_device *dev,
struct v4l2_subdev **sd);
#endif

View File

@@ -151,8 +151,8 @@
#define CIF_MI_SP_Y_FULL_YUV2RGB BIT(8)
#define CIF_MI_SP_CBCR_FULL_YUV2RGB BIT(9)
#define CIF_MI_SP_422NONCOSITEED BIT(10)
#define CIF_MI_MP_PINGPONG_ENABEL BIT(11)
#define CIF_MI_SP_PINGPONG_ENABEL BIT(12)
#define CIF_MI_MP_PINGPONG_ENABLE BIT(11)
#define CIF_MI_SP_PINGPONG_ENABLE BIT(12)
#define CIF_MI_MP_AUTOUPDATE_ENABLE BIT(13)
#define CIF_MI_SP_AUTOUPDATE_ENABLE BIT(14)
#define CIF_MI_LAST_PIXEL_SIG_ENABLE BIT(15)

View File

@@ -1438,7 +1438,7 @@ static int rkisp_isp_sd_set_selection(struct v4l2_subdev *sd,
isp_sd->out_crop = *crop;
isp_sd->out_crop.left = 0;
isp_sd->out_crop.top = 0;
dev->mpfbc_dev.crop = isp_sd->out_crop;
dev->br_dev.crop = isp_sd->out_crop;
}
} else {
if (dev->isp_ver == ISP_V20)
@@ -1446,16 +1446,14 @@ static int rkisp_isp_sd_set_selection(struct v4l2_subdev *sd,
isp_sd->out_crop = *crop;
}
/* change fmt&size of MP/SP */
/* change size of MP/SP */
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_MP,
isp_sd->out_crop.width,
isp_sd->out_crop.height,
V4L2_PIX_FMT_YUYV);
isp_sd->out_crop.height, 0);
if (dev->isp_ver != ISP_V10_1)
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_SP,
isp_sd->out_crop.width,
isp_sd->out_crop.height,
V4L2_PIX_FMT_YUYV);
isp_sd->out_crop.height, 0);
return 0;
err:
return -EINVAL;
@@ -1636,19 +1634,19 @@ static int rkisp_subdev_link_setup(struct media_entity *entity,
} else if (!strcmp(remote->entity->name, SP_VDEV_NAME)) {
stream = &dev->cap_dev.stream[RKISP_STREAM_SP];
if (flags & MEDIA_LNK_FL_ENABLED &&
dev->mpfbc_dev.linked)
dev->br_dev.linked)
goto err;
} else if (!strcmp(remote->entity->name, MP_VDEV_NAME)) {
stream = &dev->cap_dev.stream[RKISP_STREAM_MP];
if (flags & MEDIA_LNK_FL_ENABLED &&
dev->mpfbc_dev.linked)
dev->br_dev.linked)
goto err;
} else if (!strcmp(remote->entity->name, MPFBC_DEV_NAME)) {
} else if (!strcmp(remote->entity->name, BRIDGE_DEV_NAME)) {
if (flags & MEDIA_LNK_FL_ENABLED &&
(dev->cap_dev.stream[RKISP_STREAM_SP].linked ||
dev->cap_dev.stream[RKISP_STREAM_MP].linked))
goto err;
dev->mpfbc_dev.linked = flags & MEDIA_LNK_FL_ENABLED;
dev->br_dev.linked = flags & MEDIA_LNK_FL_ENABLED;
} else {
if (flags & MEDIA_LNK_FL_ENABLED) {
if (dev->isp_inp & ~(INP_DVP | rawrd))
@@ -1673,7 +1671,7 @@ err:
v4l2_err(sd, "link error %s -> %s\n"
"\tdmaread can't work with other input\n"
"\tcsi dvp can't work together\n"
"\tmpfbc can't work with mainpath/selfpath\n",
"\tbridge can't work with mainpath/selfpath\n",
local->entity->name, remote->entity->name);
return -EINVAL;
}

View File

@@ -44,6 +44,7 @@ int rkispp_allow_buffer(struct rkispp_device *dev,
struct rkispp_dummy_buffer *buf)
{
const struct vb2_mem_ops *ops = &vb2_dma_contig_memops;
unsigned long attrs = buf->is_need_vaddr ? 0 : DMA_ATTR_NO_KERNEL_MAPPING;
void *mem_priv;
int ret = 0;
@@ -52,8 +53,8 @@ int rkispp_allow_buffer(struct rkispp_device *dev,
goto err;
}
mem_priv = ops->alloc(dev->dev, 0, buf->size,
DMA_BIDIRECTIONAL, GFP_KERNEL);
mem_priv = ops->alloc(dev->dev, attrs, buf->size,
DMA_BIDIRECTIONAL, GFP_KERNEL);
if (IS_ERR_OR_NULL(mem_priv)) {
ret = -ENOMEM;
goto err;
@@ -61,7 +62,10 @@ int rkispp_allow_buffer(struct rkispp_device *dev,
buf->mem_priv = mem_priv;
buf->dma_addr = *((dma_addr_t *)ops->cookie(mem_priv));
buf->vaddr = ops->vaddr(mem_priv);
if (!attrs)
buf->vaddr = ops->vaddr(mem_priv);
if (buf->is_need_dbuf)
buf->dbuf = ops->get_dmabuf(mem_priv, O_RDWR);
v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev,
"%s buf:0x%x~0x%x size:%d\n", __func__,
(u32)buf->dma_addr, (u32)buf->dma_addr + buf->size, buf->size);
@@ -80,9 +84,14 @@ void rkispp_free_buffer(struct rkispp_device *dev,
v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev,
"%s buf:0x%x~0x%x\n", __func__,
(u32)buf->dma_addr, (u32)buf->dma_addr + buf->size);
if (buf->dbuf)
dma_buf_put(buf->dbuf);
ops->put(buf->mem_priv);
buf->size = 0;
buf->dbuf = NULL;
buf->vaddr = NULL;
buf->mem_priv = NULL;
buf->is_need_dbuf = false;
buf->is_need_vaddr = false;
}
}

View File

@@ -40,11 +40,15 @@ struct rkispp_buffer {
};
struct rkispp_dummy_buffer {
struct list_head queue;
struct list_head list;
struct dma_buf *dbuf;
dma_addr_t dma_addr;
void *mem_priv;
void *vaddr;
u32 size;
void *mem_priv;
u32 id;
bool is_need_vaddr;
bool is_need_dbuf;
};
extern int rkispp_debug;

View File

@@ -40,6 +40,10 @@ int rkispp_debug;
module_param_named(debug, rkispp_debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-3)");
static int rkisp_ispp_mode = ISP_ISPP_422 | ISP_ISPP_FBC;
module_param_named(mode, rkisp_ispp_mode, int, 0644);
MODULE_PARM_DESC(mode, "isp->ispp mode: bit0 fbc, bit1 yuv422, bit2 quick");
static char rkispp_version[RKISPP_VERNO_LEN];
module_param_string(version, rkispp_version, RKISPP_VERNO_LEN, 0444);
MODULE_PARM_DESC(version, "version number");
@@ -82,13 +86,12 @@ static void get_remote_node_dev(struct rkispp_device *ispp_dev)
of_node_full_name(remote));
continue;
} else {
rkisp_get_mpfbc_sd(remote_dev, &sd);
rkisp_get_bridge_sd(remote_dev, &sd);
if (!sd) {
dev_err(dev, "Failed to get remote mpfbc sd\n");
dev_err(dev, "Failed to get isp bridge sd\n");
} else {
ispp_dev->ispp_sdev.remote_sd = sd;
dev_info(dev, "get remote mpfbc sd:%s\n",
sd->name);
v4l2_set_subdev_hostdata(sd, &ispp_dev->ispp_sdev.sd);
break;
}
}
@@ -225,6 +228,7 @@ static int rkispp_enable_sys_clk(struct rkispp_device *ispp_dev)
{
int i, ret = -EINVAL;
ispp_dev->isp_mode = rkisp_ispp_mode;
for (i = 0; i < ispp_dev->clks_num; i++) {
ret = clk_prepare_enable(ispp_dev->clks[i]);
if (ret < 0)

View File

@@ -52,5 +52,6 @@ struct rkispp_device {
/* lock for fec and ispp irq */
spinlock_t irq_lock;
enum rkispp_input inp;
u32 isp_mode;
};
#endif

View File

@@ -12,6 +12,27 @@
#include "dev.h"
#include "regs.h"
void rkispp_free_pool(struct rkispp_stream_vdev *vdev)
{
const struct vb2_mem_ops *ops = &vb2_dma_contig_memops;
struct rkispp_isp_buf_pool *buf;
int i, j;
for (i = 0; i < RKISPP_BUF_POOL_MAX; i++) {
buf = &vdev->pool[i];
if (!buf->dbufs)
break;
for (j = 0; j < GROUP_BUF_MAX; j++) {
if (buf->mem_priv[j]) {
ops->unmap_dmabuf(buf->mem_priv[j]);
ops->detach_dmabuf(buf->mem_priv[j]);
buf->mem_priv[j] = NULL;
}
}
buf->dbufs = NULL;
}
}
u32 cal_fec_mesh(u32 width, u32 height, u32 mode)
{
u32 mesh_size, mesh_left_height;
@@ -232,92 +253,73 @@ err:
return -EINVAL;
}
static int rkispp_s_rx_buffer(struct rkispp_subdev *ispp_sdev)
{
const struct vb2_mem_ops *ops = &vb2_dma_contig_memops;
struct rkispp_device *dev = ispp_sdev->dev;
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
struct rkispp_dummy_buffer *buf;
struct dma_buf *dbuf;
void *size;
int ret;
if (vdev->module_ens & ISPP_MODULE_TNR) {
buf = &vdev->tnr_buf.pic_cur;
size = &buf->size;
dbuf = ops->get_dmabuf(buf->mem_priv, O_RDWR);
ret = v4l2_subdev_call(ispp_sdev->remote_sd,
video, s_rx_buffer, dbuf, size);
if (ret)
return ret;
buf = &vdev->tnr_buf.gain_cur;
size = &buf->size;
dbuf = ops->get_dmabuf(buf->mem_priv, O_RDWR);
if ((vdev->module_ens & ISPP_MODULE_TNR_3TO1) ==
ISPP_MODULE_TNR_3TO1) {
ret = v4l2_subdev_call(ispp_sdev->remote_sd,
video, s_rx_buffer, dbuf, size);
if (ret)
return ret;
buf = &vdev->tnr_buf.pic_next;
size = &buf->size;
dbuf = ops->get_dmabuf(buf->mem_priv, O_RDWR);
ret = v4l2_subdev_call(ispp_sdev->remote_sd,
video, s_rx_buffer, dbuf, size);
if (ret)
return ret;
buf = &vdev->tnr_buf.gain_next;
size = &buf->size;
dbuf = ops->get_dmabuf(buf->mem_priv, O_RDWR);
}
} else {
buf = &vdev->nr_buf.pic_cur;
size = &buf->size;
dbuf = ops->get_dmabuf(buf->mem_priv, O_RDWR);
ret = v4l2_subdev_call(ispp_sdev->remote_sd,
video, s_rx_buffer, dbuf, size);
if (ret)
return ret;
buf = &vdev->nr_buf.gain_cur;
size = &buf->size;
dbuf = ops->get_dmabuf(buf->mem_priv, O_RDWR);
}
return v4l2_subdev_call(ispp_sdev->remote_sd,
video, s_rx_buffer, dbuf, size);
}
static int rkispp_sd_s_stream(struct v4l2_subdev *sd, int on)
{
struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
struct rkispp_device *dev = ispp_sdev->dev;
struct rkispp_stream *stream;
int ret, i;
for (i = 0; i < STREAM_MAX; i++) {
stream = &dev->stream_vdev.stream[i];
if (stream->streaming)
break;
}
if (i == STREAM_MAX) {
v4l2_err(&dev->v4l2_dev,
"no video start before subdev stream on\n");
return -EINVAL;
}
int ret;
v4l2_dbg(1, rkispp_debug, &ispp_sdev->dev->v4l2_dev,
"s_stream on:%d\n", on);
if (on) {
ret = rkispp_s_rx_buffer(ispp_sdev);
if (ret)
return ret;
ret = v4l2_subdev_call(ispp_sdev->remote_sd,
video, s_stream, on);
if (!ret)
ispp_sdev->state = on;
if ((on && ret) || (!on && !ret))
rkispp_free_pool(&dev->stream_vdev);
return ret;
}
static int rkispp_sd_s_rx_buffer(struct v4l2_subdev *sd,
void *buf, unsigned int *size)
{
const struct vb2_mem_ops *ops = &vb2_dma_contig_memops;
struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
struct rkispp_device *dev = ispp_sdev->dev;
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
struct rkisp_ispp_buf *dbufs = buf;
struct rkispp_isp_buf_pool *pool;
u32 i, val = (vdev->module_ens & ISPP_MODULE_TNR) ?
ISPP_MODULE_TNR : ISPP_MODULE_NR;
int ret = 0;
void *mem;
/* size isn't using now */
if (!dbufs)
return -EINVAL;
if (ispp_sdev->state == ISPP_START) {
rkispp_module_work_event(dev, dbufs, NULL, val, false);
return ret;
}
return v4l2_subdev_call(ispp_sdev->remote_sd,
video, s_stream, on);
/* init dma buf pool */
for (i = 0; i < RKISPP_BUF_POOL_MAX; i++) {
pool = &vdev->pool[i];
if (!pool->dbufs)
break;
}
pool->dbufs = dbufs;
for (i = 0; i < GROUP_BUF_MAX; i++) {
mem = ops->attach_dmabuf(dev->dev, dbufs->dbuf[i],
dbufs->dbuf[i]->size, DMA_BIDIRECTIONAL);
if (IS_ERR(mem)) {
ret = PTR_ERR(mem);
goto err;
}
pool->mem_priv[i] = mem;
ret = ops->map_dmabuf(mem);
if (ret)
goto err;
pool->dma[i] = *((dma_addr_t *)ops->cookie(mem));
v4l2_dbg(1, rkispp_debug, sd,
"dma[%d]:0x%x\n", i, pool->dma[i]);
}
return 0;
err:
rkispp_free_pool(vdev);
return ret;
}
static int rkispp_sd_s_power(struct v4l2_subdev *sd, int on)
@@ -348,8 +350,8 @@ static int rkispp_sd_s_power(struct v4l2_subdev *sd, int on)
writel(SW_FEC2DDR_DIS, base + RKISPP_FEC_CORE_CTRL);
writel(0xfffffff, base + RKISPP_CTRL_INT_MSK);
writel(GATE_DIS_ALL, base + RKISPP_CTRL_CLKGATE);
//usleep_range(1000, 1200);
//writel(0, base + RKISPP_CTRL_CLKGATE);
usleep_range(100, 120);
writel(GATE_DIS_NR, base + RKISPP_CTRL_CLKGATE);
if (ispp_dev->inp == INP_ISP) {
struct v4l2_subdev_format fmt;
struct v4l2_subdev_selection sel;
@@ -402,6 +404,7 @@ static int rkispp_sd_s_power(struct v4l2_subdev *sd, int on)
v4l2_err(&ispp_dev->v4l2_dev,
"%s runtime put failed:%d\n",
__func__, ret);
ispp_sdev->state = ISPP_STOP;
}
return ret;
@@ -424,6 +427,7 @@ static const struct v4l2_subdev_pad_ops rkispp_sd_pad_ops = {
static const struct v4l2_subdev_video_ops rkispp_sd_video_ops = {
.s_stream = rkispp_sd_s_stream,
.s_rx_buffer = rkispp_sd_s_rx_buffer,
};
static const struct v4l2_subdev_core_ops rkispp_sd_core_ops = {
@@ -446,7 +450,7 @@ int rkispp_register_subdev(struct rkispp_device *dev,
memset(ispp_sdev, 0, sizeof(*ispp_sdev));
ispp_sdev->dev = dev;
sd = &ispp_sdev->sd;
ispp_sdev->state = ISPP_STOP;
v4l2_subdev_init(sd, &rkispp_sd_ops);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->entity.ops = &rkispp_sd_media_ops;

View File

@@ -16,6 +16,11 @@ enum rkispp_pad {
RKISPP_PAD_MAX
};
enum rkispp_state {
ISPP_STOP = 0,
ISPP_START,
};
struct isppsd_fmt {
u32 mbus_code;
u32 fourcc;
@@ -32,6 +37,7 @@ struct rkispp_subdev {
struct v4l2_mbus_framefmt in_fmt;
struct isppsd_fmt out_fmt;
atomic_t frm_sync_seq;
enum rkispp_state state;
};
u32 cal_fec_mesh(u32 width, u32 height, u32 mode);

View File

@@ -114,6 +114,8 @@
#define RKISPP_TNR_CORE_SCALE_CL1 (RKISPP_TNR + 0x0150)
#define RKISPP_TNR_CORE_SCALE_CL2 (RKISPP_TNR + 0x0154)
#define RKISPP_TNR_CORE_WEIGHT (RKISPP_TNR + 0x0158)
#define RKISPP_TNR_TILE_CNT (RKISPP_TNR + 0x01c0)
#define RKISPP_TNR_STATE (RKISPP_TNR + 0x01c4)
#define RKISPP_NR 0x0400
#define RKISPP_NR_CTRL (RKISPP_NR + 0x0000)
@@ -199,6 +201,8 @@
#define RKISPP_NR_YNR_HSTV_Y_16 (RKISPP_NR + 0x01E0)
#define RKISPP_NR_YNR_ST_SCALE_LV1_LV2 (RKISPP_NR + 0x01E4)
#define RKISPP_NR_YNR_ST_SCALE_LV3 (RKISPP_NR + 0x01E8)
#define RKISPP_NR_BLOCK_CNT (RKISPP_NR + 0x01f0)
#define RKISPP_NR_BUFFER_READY (RKISPP_NR + 0x01f4)
#define RKISPP_SHARP 0x0600
#define RKISPP_SHARP_CTRL (RKISPP_SHARP + 0x0000)

View File

@@ -28,7 +28,7 @@ static void update_addr(struct rkispp_stats_vdev *stats_vdev)
if (!stats_vdev->next_buf) {
dummy_buf = &stats_vdev->dummy_buf;
if (!dummy_buf->vaddr)
if (!dummy_buf->mem_priv)
return;
writel(dummy_buf->dma_addr, base + RKISPP_ORB_WR_BASE);

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@
#include "common.h"
#define RKISPP_BUF_POOL_MAX (RKISP_ISPP_BUF_MAX + 1)
struct rkispp_stream;
/*
@@ -73,24 +74,55 @@ enum stream_type {
STREAM_OUTPUT,
};
/* tnr internal using buf */
struct in_tnr_buf {
struct rkispp_dummy_buffer pic_cur;
struct rkispp_dummy_buffer pic_next;
struct rkispp_dummy_buffer gain_cur;
struct rkispp_dummy_buffer gain_next;
struct rkispp_dummy_buffer gain_kg;
struct rkispp_dummy_buffer iir;
struct rkispp_dummy_buffer pic_wr;
struct rkispp_dummy_buffer gain_wr;
/* internal using buf */
struct rkispp_isp_buf_pool {
struct rkisp_ispp_buf *dbufs;
void *mem_priv[GROUP_BUF_MAX];
dma_addr_t dma[GROUP_BUF_MAX];
};
struct in_tnr_buf {
struct rkispp_dummy_buffer iir;
struct rkispp_dummy_buffer gain_kg;
struct rkispp_dummy_buffer wr[RKISP_ISPP_BUF_MAX][GROUP_BUF_MAX];
};
/* nr internal using buf */
struct in_nr_buf {
struct rkispp_dummy_buffer pic_cur;
struct rkispp_dummy_buffer gain_cur;
struct rkispp_dummy_buffer pic_wr;
struct rkispp_dummy_buffer tmp_yuv;
struct rkispp_dummy_buffer wr[RKISP_ISPP_BUF_MAX];
};
struct tnr_module {
struct in_tnr_buf buf;
struct list_head list_rd;
struct list_head list_wr;
spinlock_t buf_lock;
struct rkisp_ispp_buf *cur_rd;
struct rkisp_ispp_buf *nxt_rd;
struct rkisp_ispp_buf *cur_wr;
u32 uv_offset;
bool is_end;
bool is_3to1;
};
struct nr_module {
struct in_nr_buf buf;
struct list_head list_rd;
struct list_head list_wr;
spinlock_t buf_lock;
struct rkisp_ispp_buf *cur_rd;
struct rkispp_dummy_buffer *cur_wr;
u32 uv_offset;
bool is_end;
};
struct fec_module {
struct list_head list_rd;
struct rkispp_dummy_buffer *cur_rd;
spinlock_t buf_lock;
u32 uv_offset;
bool is_end;
};
/* fec internal using buf */
@@ -134,22 +166,29 @@ struct rkispp_stream {
struct capture_fmt out_cap_fmt;
struct v4l2_pix_format_mplane out_fmt;
u8 last_module;
u8 streaming;
u8 stopping;
u8 linked;
bool streaming;
bool stopping;
bool linked;
bool is_upd;
};
/* rkispp stream device */
struct rkispp_stream_vdev {
struct rkispp_stream stream[STREAM_MAX];
struct in_tnr_buf tnr_buf;
struct in_nr_buf nr_buf;
struct rkispp_isp_buf_pool pool[RKISPP_BUF_POOL_MAX];
struct tnr_module tnr;
struct nr_module nr;
struct fec_module fec;
struct in_fec_buf fec_buf;
atomic_t refcnt;
u32 module_ens;
u8 is_update_manual;
u32 irq_ends;
};
void rkispp_free_pool(struct rkispp_stream_vdev *vdev);
void rkispp_module_work_event(struct rkispp_device *dev,
void *buf_rd, void *buf_wr,
u32 module, bool is_isr);
void rkispp_isr(u32 mis_val, struct rkispp_device *dev);
void rkispp_unregister_stream_vdevs(struct rkispp_device *dev);
int rkispp_register_stream_vdevs(struct rkispp_device *dev);