From 6778948f9de86c3cfaf36725a7c87dcff9ba247f Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 08:20:59 +0000 Subject: [PATCH] kernel_5.10 no rt --- kernel/drivers/media/platform/rockchip/cif/capture.c | 7191 +++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 5,885 insertions(+), 1,306 deletions(-) diff --git a/kernel/drivers/media/platform/rockchip/cif/capture.c b/kernel/drivers/media/platform/rockchip/cif/capture.c index 25c664d..983d675 100644 --- a/kernel/drivers/media/platform/rockchip/cif/capture.c +++ b/kernel/drivers/media/platform/rockchip/cif/capture.c @@ -19,11 +19,14 @@ #include <media/videobuf2-dma-sg.h> #include <soc/rockchip/rockchip-system-status.h> #include <dt-bindings/soc/rockchip-system-status.h> +#include <soc/rockchip/rockchip_iommu.h> #include "dev.h" #include "mipi-csi2.h" +#include "common.h" +#include "rkcif-externel.h" -#define CIF_REQ_BUFS_MIN 3 +#define CIF_REQ_BUFS_MIN 1 #define CIF_MIN_WIDTH 64 #define CIF_MIN_HEIGHT 64 #define CIF_MAX_WIDTH 8192 @@ -33,6 +36,7 @@ #define RKCIF_PLANE_Y 0 #define RKCIF_PLANE_CBCR 1 +#define RKCIF_MAX_PLANE 3 #define STREAM_PAD_SINK 0 #define STREAM_PAD_SOURCE 1 @@ -146,10 +150,18 @@ .csi_fmt_val = CSI_WRDDR_TYPE_RGB888, .fmt_type = CIF_FMT_TYPE_RAW, }, { + .fourcc = V4L2_PIX_FMT_BGR24, + .cplanes = 1, + .mplanes = 1, + .bpp = { 24 }, + .csi_fmt_val = CSI_WRDDR_TYPE_RGB888, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { .fourcc = V4L2_PIX_FMT_RGB565, .cplanes = 1, .mplanes = 1, .bpp = { 16 }, + .csi_fmt_val = CSI_WRDDR_TYPE_RGB565, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_BGR666, @@ -262,6 +274,30 @@ .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_RAW, }, { + .fourcc = V4L2_PIX_FMT_SGBRG16, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 16, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG16, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 16, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB16, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 16, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { .fourcc = V4L2_PIX_FMT_Y16, .cplanes = 1, .mplanes = 1, @@ -293,8 +329,51 @@ .raw_bpp = 16, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_Y12, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 12, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_Y10, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 10, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW10, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB16, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 16, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG16, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 16, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG16, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 16, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR16, + .cplanes = 1, + .mplanes = 1, + .bpp = { 16 }, + .raw_bpp = 16, + .fmt_type = CIF_FMT_TYPE_RAW, } - /* TODO: We can support NV12M/NV21M/NV16M/NV61M too */ }; @@ -432,6 +511,14 @@ .csi_fmt_val = CSI_WRDDR_TYPE_RGB888, .field = V4L2_FIELD_NONE, }, { + .mbus_code = MEDIA_BUS_FMT_BGR888_1X24, + .csi_fmt_val = CSI_WRDDR_TYPE_RGB888, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_RGB565_1X16, + .csi_fmt_val = CSI_WRDDR_TYPE_RGB565, + .field = V4L2_FIELD_NONE, + }, { .mbus_code = MEDIA_BUS_FMT_Y8_1X8, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_8, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, @@ -463,6 +550,143 @@ .field = V4L2_FIELD_NONE, } }; + +static int rkcif_output_fmt_check(struct rkcif_stream *stream, + const struct cif_output_fmt *output_fmt) +{ + const struct cif_input_fmt *input_fmt = stream->cif_fmt_in; + struct csi_channel_info *channel = &stream->cifdev->channels[stream->id]; + int ret = -EINVAL; + + switch (input_fmt->mbus_code) { + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: + if (output_fmt->fourcc == V4L2_PIX_FMT_NV16 || + output_fmt->fourcc == V4L2_PIX_FMT_NV61 || + output_fmt->fourcc == V4L2_PIX_FMT_NV12 || + output_fmt->fourcc == V4L2_PIX_FMT_NV21 || + output_fmt->fourcc == V4L2_PIX_FMT_YUYV || + output_fmt->fourcc == V4L2_PIX_FMT_YVYU || + output_fmt->fourcc == V4L2_PIX_FMT_UYVY || + output_fmt->fourcc == V4L2_PIX_FMT_VYUY) + ret = 0; + break; + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_Y8_1X8: + if (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB8 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG8 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG8 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR8 || + output_fmt->fourcc == V4L2_PIX_FMT_GREY) + ret = 0; + break; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_Y10_1X10: + if (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB10 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG10 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG10 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR10 || + output_fmt->fourcc == V4L2_PIX_FMT_Y10) + ret = 0; + break; + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + case MEDIA_BUS_FMT_Y12_1X12: + if (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB12 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG12 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG12 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR12 || + output_fmt->fourcc == V4L2_PIX_FMT_Y12) + ret = 0; + break; + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_BGR888_1X24: + if (output_fmt->fourcc == V4L2_PIX_FMT_RGB24 || + output_fmt->fourcc == V4L2_PIX_FMT_BGR24) + ret = 0; + break; + case MEDIA_BUS_FMT_RGB565_1X16: + if (output_fmt->fourcc == V4L2_PIX_FMT_RGB565) + ret = 0; + break; + case MEDIA_BUS_FMT_EBD_1X8: + if (output_fmt->fourcc == V4l2_PIX_FMT_EBD8 || + (channel->data_bit == 8 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB8 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG8 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG8 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR8)) || + (channel->data_bit == 10 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB10 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG10 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG10 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR10)) || + (channel->data_bit == 12 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB12 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG12 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG12 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR12)) || + (channel->data_bit == 16 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB16 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG16 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG16 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR16))) + ret = 0; + break; + case MEDIA_BUS_FMT_SPD_2X8: + if (output_fmt->fourcc == V4l2_PIX_FMT_SPD16 || + (channel->data_bit == 8 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB8 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG8 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG8 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR8)) || + (channel->data_bit == 10 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB10 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG10 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG10 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR10)) || + (channel->data_bit == 12 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB12 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG12 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG12 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR12)) || + (channel->data_bit == 16 && + (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB16 || + output_fmt->fourcc == V4L2_PIX_FMT_SGRBG16 || + output_fmt->fourcc == V4L2_PIX_FMT_SGBRG16 || + output_fmt->fourcc == V4L2_PIX_FMT_SBGGR16))) + ret = 0; + break; + default: + break; + } + if (ret) + v4l2_err(&stream->cifdev->v4l2_dev, + "input mbus_code 0x%x, can't transform to %c%c%c%c\n", + input_fmt->mbus_code, + output_fmt->fourcc & 0xff, + (output_fmt->fourcc >> 8) & 0xff, + (output_fmt->fourcc >> 16) & 0xff, + (output_fmt->fourcc >> 24) & 0xff); + return ret; +} + +static int rkcif_stop_dma_capture(struct rkcif_stream *stream); + +struct rkcif_rx_buffer *to_cif_rx_buf(struct rkisp_rx_buf *dbufs) +{ + return container_of(dbufs, struct rkcif_rx_buffer, dbufs); +} static struct v4l2_subdev *get_remote_sensor(struct rkcif_stream *stream, u16 *index) { @@ -575,7 +799,8 @@ case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_YVYU8_2X8: return 0x1e; - case MEDIA_BUS_FMT_RGB888_1X24: { + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_BGR888_1X24: if (dsi_input) { if (cmd_mode_en) /* dsi command mode*/ return 0x39; @@ -584,7 +809,15 @@ } else { return 0x24; } - } + case MEDIA_BUS_FMT_RGB565_1X16: + if (dsi_input) { + if (cmd_mode_en) /* dsi command mode*/ + return 0x39; + else /* dsi video mode */ + return 0x0e; + } else { + return 0x22; + } case MEDIA_BUS_FMT_EBD_1X8: return 0x12; case MEDIA_BUS_FMT_SPD_2X8: @@ -600,6 +833,8 @@ switch (fmt_in->csi_fmt_val) { case CSI_WRDDR_TYPE_RGB888: return 24; + case CSI_WRDDR_TYPE_RGB565: + return 16; case CSI_WRDDR_TYPE_RAW10: case CSI_WRDDR_TYPE_RAW12: return 4; @@ -611,51 +846,61 @@ } } -static const struct -cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd, struct v4l2_rect *rect, - u32 pad, int *vc) +const struct +cif_input_fmt *rkcif_get_input_fmt(struct rkcif_device *dev, struct v4l2_rect *rect, + u32 pad_id, struct csi_channel_info *csi_info) { struct v4l2_subdev_format fmt; + struct v4l2_subdev *sd = dev->terminal_sensor.sd; + struct rkmodule_channel_info ch_info = {0}; + struct rkmodule_capture_info capture_info; int ret; u32 i; - struct rkmodule_vc_fmt_info vc_info = {0}; - ret = v4l2_subdev_call(sd, - core, ioctl, - RKMODULE_GET_VC_FMT_INFO, - &vc_info); - if (ret < 0) - v4l2_warn(sd->v4l2_dev, - "get sensor vc info failed, maybe not support\n"); - - fmt.pad = pad; + fmt.pad = 0; fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; fmt.reserved[0] = 0; + fmt.format.field = V4L2_FIELD_NONE; ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) { v4l2_warn(sd->v4l2_dev, "sensor fmt invalid, set to default size\n"); goto set_default; } - - /* v4l2_subdev_format reserved[0] - * using as mipi virtual channel - */ - switch (fmt.reserved[0]) { - case V4L2_MBUS_CSI2_CHANNEL_3: - *vc = 3; - break; - case V4L2_MBUS_CSI2_CHANNEL_2: - *vc = 2; - break; - case V4L2_MBUS_CSI2_CHANNEL_1: - *vc = 1; - break; - case V4L2_MBUS_CSI2_CHANNEL_0: - *vc = 0; - break; - default: - *vc = -1; + ch_info.index = pad_id; + ret = v4l2_subdev_call(sd, + core, ioctl, + RKMODULE_GET_CHANNEL_INFO, + &ch_info); + if (!ret) { + fmt.format.width = ch_info.width; + fmt.format.height = ch_info.height; + fmt.format.code = ch_info.bus_fmt; + switch (ch_info.vc) { + case V4L2_MBUS_CSI2_CHANNEL_3: + csi_info->vc = 3; + break; + case V4L2_MBUS_CSI2_CHANNEL_2: + csi_info->vc = 2; + break; + case V4L2_MBUS_CSI2_CHANNEL_1: + csi_info->vc = 1; + break; + case V4L2_MBUS_CSI2_CHANNEL_0: + csi_info->vc = 0; + break; + default: + csi_info->vc = 0xff; + } + if (ch_info.bus_fmt == MEDIA_BUS_FMT_SPD_2X8 || + ch_info.bus_fmt == MEDIA_BUS_FMT_EBD_1X8) { + if (ch_info.data_type > 0) + csi_info->data_type = ch_info.data_type; + if (ch_info.data_bit > 0) + csi_info->data_bit = ch_info.data_bit; + } + } else { + csi_info->vc = 0xff; } v4l2_dbg(1, rkcif_debug, sd->v4l2_dev, @@ -666,7 +911,26 @@ rect->top = 0; rect->width = fmt.format.width; rect->height = fmt.format.height; - + ret = v4l2_subdev_call(sd, + core, ioctl, + RKMODULE_GET_CAPTURE_MODE, + &capture_info); + if (!ret) { + if (capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + dev->hw_dev->is_rk3588s2) { + for (i = 0; i < capture_info.multi_dev.dev_num; i++) { + if (capture_info.multi_dev.dev_idx[i] == 0) + capture_info.multi_dev.dev_idx[i] = 2; + else if (capture_info.multi_dev.dev_idx[i] == 2) + capture_info.multi_dev.dev_idx[i] = 4; + else if (capture_info.multi_dev.dev_idx[i] == 3) + capture_info.multi_dev.dev_idx[i] = 5; + } + } + csi_info->capture_info = capture_info; + } else { + csi_info->capture_info.mode = RKMODULE_CAPTURE_MODE_NONE; + } for (i = 0; i < ARRAY_SIZE(in_fmts); i++) if (fmt.format.code == in_fmts[i].mbus_code && fmt.format.field == in_fmts[i].field) @@ -683,8 +947,8 @@ return NULL; } -static const struct -cif_output_fmt *find_output_fmt(struct rkcif_stream *stream, u32 pixelfmt) +const struct +cif_output_fmt *rkcif_find_output_fmt(struct rkcif_stream *stream, u32 pixelfmt) { const struct cif_output_fmt *fmt; u32 i; @@ -717,6 +981,31 @@ break; default: index = CIF_REG_MIPI_LVDS_ID0_CTRL0; + break; + } + + return index; +} + +static enum cif_reg_index get_reg_index_of_lvds_id_ctrl0(int channel_id) +{ + enum cif_reg_index index; + + switch (channel_id) { + case 0: + index = CIF_REG_LVDS_ID0_CTRL0; + break; + case 1: + index = CIF_REG_LVDS_ID1_CTRL0; + break; + case 2: + index = CIF_REG_LVDS_ID2_CTRL0; + break; + case 3: + index = CIF_REG_LVDS_ID3_CTRL0; + break; + default: + index = CIF_REG_LVDS_ID0_CTRL0; break; } @@ -1173,12 +1462,50 @@ return index; } +int rkcif_get_linetime(struct rkcif_stream *stream) +{ + struct rkcif_device *cif_dev = stream->cifdev; + struct rkcif_sensor_info *sensor = &cif_dev->terminal_sensor; + u32 numerator, denominator; + u32 def_fps = 0; + int line_time = 0; + int vblank_def = 0; + int vblank_curr = 0; + + numerator = sensor->fi.interval.numerator; + denominator = sensor->fi.interval.denominator; + if (!numerator || !denominator) { + v4l2_err(&cif_dev->v4l2_dev, + "get frame interval fail, numerator %d, denominator %d\n", + numerator, denominator); + return -EINVAL; + } + def_fps = denominator / numerator; + if (!def_fps) { + v4l2_err(&cif_dev->v4l2_dev, + "get fps fail, numerator %d, denominator %d\n", + numerator, denominator); + return -EINVAL; + } + vblank_def = rkcif_get_sensor_vblank_def(cif_dev); + vblank_curr = rkcif_get_sensor_vblank(cif_dev); + if (!vblank_def || !vblank_curr) { + v4l2_err(&cif_dev->v4l2_dev, + "get vblank fail, vblank_def %d, vblank_curr %d\n", + vblank_def, vblank_curr); + return -EINVAL; + } + line_time = div_u64(1000000000, def_fps); + line_time = div_u64(line_time, vblank_def + sensor->raw_rect.height); + return line_time; +} + /***************************** stream operations ******************************/ static int rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream, - enum rkcif_yuvaddr_state stat) + enum rkcif_yuvaddr_state stat) { struct rkcif_device *dev = stream->cifdev; - struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; struct rkcif_buffer *buffer = NULL; u32 frm_addr_y = CIF_REG_DVP_FRM0_ADDR_Y; u32 frm_addr_uv = CIF_REG_DVP_FRM0_ADDR_UV; @@ -1273,12 +1600,696 @@ } else { ret = -EINVAL; } - v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, - "not active buffer, frame Drop\n"); + dev->err_state |= (RKCIF_ERR_ID0_NOT_BUF << stream->id); + dev->irq_stats.not_active_buf_cnt[stream->id]++; } } spin_unlock_irqrestore(&stream->vbq_lock, flags); return ret; +} + +static void rkcif_rx_buffer_free(struct rkcif_stream *stream) +{ + struct media_pad *pad = NULL; + struct v4l2_subdev *sd; + struct rkisp_rx_buf *dbufs; + struct rkcif_device *dev = stream->cifdev; + + if (dev->sditf[0] && dev->sditf[0]->sd.entity.num_links) { + if (dev->sditf[0]->is_combine_mode) + pad = media_entity_remote_pad(&dev->sditf[0]->pads[1]); + else + pad = media_entity_remote_pad(&dev->sditf[0]->pads[0]); + } else { + return; + } + + if (pad) + sd = media_entity_to_v4l2_subdev(pad->entity); + else + return; + + while (!list_empty(&stream->rx_buf_head_vicap)) { + dbufs = list_first_entry(&stream->rx_buf_head_vicap, struct rkisp_rx_buf, list); + if (dbufs->is_init) + v4l2_subdev_call(sd, core, ioctl, + RKISP_VICAP_CMD_RX_BUFFER_FREE, dbufs); + dma_buf_put(dbufs->dbuf); + list_del(&dbufs->list); + kfree(dbufs); + } +} + +static void rkcif_s_rx_buffer(struct rkcif_device *dev, struct rkisp_rx_buf *dbufs) +{ + struct media_pad *pad = NULL; + struct v4l2_subdev *sd; + struct rkcif_rx_buffer *rx_buf = NULL; + + if (dev->sditf[0]) { + if (dev->sditf[0]->is_combine_mode) + pad = media_entity_remote_pad(&dev->sditf[0]->pads[1]); + else + pad = media_entity_remote_pad(&dev->sditf[0]->pads[0]); + } else { + return; + } + if (pad) + sd = media_entity_to_v4l2_subdev(pad->entity); + else + return; + if (dev->rdbk_debug && + dbufs->sequence < 15) { + rx_buf = to_cif_rx_buf(dbufs); + v4l2_info(&dev->v4l2_dev, + "s_buf seq %d type %d, dma addr %x, %lld\n", + dbufs->sequence, dbufs->type, (u32)rx_buf->dummy.dma_addr, + ktime_get_ns()); + } + v4l2_subdev_call(sd, video, s_rx_buffer, dbufs, NULL); +} + +static void rkcif_enable_skip_frame(struct rkcif_stream *stream, int cap_m, int skip_n) +{ + struct rkcif_device *dev = stream->cifdev; + u32 val = 0; + + val = rkcif_read_register(dev, CIF_REG_MIPI_LVDS_CTRL); + val &= 0xc00fffff; + val |= cap_m << RKCIF_CAP_SHIFT | skip_n << RKCIF_SKIP_SHIFT | RKCIF_SKIP_EN(stream->id); + rkcif_write_register(dev, CIF_REG_MIPI_LVDS_CTRL, val); + stream->skip_info.skip_en = true; +} + +static void rkcif_disable_skip_frame(struct rkcif_stream *stream) +{ struct rkcif_device *dev = stream->cifdev; + u32 val = 0; + + val = rkcif_read_register(dev, CIF_REG_MIPI_LVDS_CTRL); + val &= ~(RKCIF_SKIP_EN(stream->id)); + rkcif_write_register(dev, CIF_REG_MIPI_LVDS_CTRL, val); + stream->skip_info.skip_en = false; +} + +static void rkcif_rdbk_with_tools(struct rkcif_stream *stream, + struct rkcif_rx_buffer *active_buf) +{ + unsigned long flags; + + spin_lock_irqsave(&stream->tools_vdev->vbq_lock, flags); + if (stream->tools_vdev->state == RKCIF_STATE_STREAMING) { + list_add_tail(&active_buf->list, &stream->tools_vdev->buf_done_head); + if (!work_busy(&stream->tools_vdev->work)) + schedule_work(&stream->tools_vdev->work); + } + spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags); +} + +static void rkcif_rdbk_frame_end_toisp(struct rkcif_stream *stream, + struct rkcif_rx_buffer *buffer) +{ + struct rkcif_device *dev = stream->cifdev; + struct rkcif_sensor_info *sensor = &stream->cifdev->terminal_sensor; + u32 denominator, numerator; + u64 l_ts, m_ts, s_ts, time = 30000000LL; + int ret, fps = -1; + unsigned long flags; + + spin_lock_irqsave(&dev->hdr_lock, flags); + if (dev->rdbk_rx_buf[stream->id]) { + list_add_tail(&dev->rdbk_rx_buf[stream->id]->list, &stream->rx_buf_head); + dev->rdbk_rx_buf[stream->id] = buffer; + } else { + dev->rdbk_rx_buf[stream->id] = buffer; + } + + numerator = sensor->fi.interval.numerator; + denominator = sensor->fi.interval.denominator; + if (denominator && numerator) + time = numerator * 1000 / denominator * 1000 * 1000; + + if (dev->hdr.hdr_mode == HDR_X3 && + dev->rdbk_rx_buf[RDBK_L] && + dev->rdbk_rx_buf[RDBK_M] && + dev->rdbk_rx_buf[RDBK_S]) { + l_ts = dev->rdbk_rx_buf[RDBK_L]->fe_timestamp; + m_ts = dev->rdbk_rx_buf[RDBK_M]->fe_timestamp; + s_ts = dev->rdbk_rx_buf[RDBK_S]->fe_timestamp; + + if (m_ts < l_ts || s_ts < m_ts) { + v4l2_err(&dev->v4l2_dev, + "s/m/l frame err, timestamp s:%lld m:%lld l:%lld\n", + s_ts, m_ts, l_ts); + goto RDBK_TOISP_UNMATCH; + } + + if ((m_ts - l_ts) > time || (s_ts - m_ts) > time) { + ret = v4l2_subdev_call(sensor->sd, + video, + g_frame_interval, + &sensor->fi); + if (!ret) { + denominator = sensor->fi.interval.denominator; + numerator = sensor->fi.interval.numerator; + if (denominator && numerator) { + time = numerator * 1000 / denominator * 1000 * 1000; + fps = denominator / numerator; + } + } + + if ((m_ts - l_ts) > time || (s_ts - m_ts) > time) { + v4l2_err(&dev->v4l2_dev, + "timestamp no match, s:%lld m:%lld l:%lld, fps:%d\n", + s_ts, m_ts, l_ts, fps); + goto RDBK_TOISP_UNMATCH; + } + } + dev->rdbk_rx_buf[RDBK_M]->dbufs.sequence = dev->rdbk_rx_buf[RDBK_L]->dbufs.sequence; + dev->rdbk_rx_buf[RDBK_S]->dbufs.sequence = dev->rdbk_rx_buf[RDBK_L]->dbufs.sequence; + rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_L]->dbufs); + rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_M]->dbufs); + rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_S]->dbufs); + rkcif_rdbk_with_tools(&dev->stream[RDBK_L], dev->rdbk_rx_buf[RDBK_L]); + rkcif_rdbk_with_tools(&dev->stream[RDBK_M], dev->rdbk_rx_buf[RDBK_M]); + rkcif_rdbk_with_tools(&dev->stream[RDBK_S], dev->rdbk_rx_buf[RDBK_S]); + atomic_dec(&dev->stream[RDBK_L].buf_cnt); + atomic_dec(&dev->stream[RDBK_M].buf_cnt); + atomic_dec(&dev->stream[RDBK_S].buf_cnt); + dev->rdbk_rx_buf[RDBK_L] = NULL; + dev->rdbk_rx_buf[RDBK_M] = NULL; + dev->rdbk_rx_buf[RDBK_S] = NULL; + } else if (dev->hdr.hdr_mode == HDR_X2 && + dev->rdbk_rx_buf[RDBK_L] && dev->rdbk_rx_buf[RDBK_M]) { + l_ts = dev->rdbk_rx_buf[RDBK_L]->fe_timestamp; + s_ts = dev->rdbk_rx_buf[RDBK_M]->fe_timestamp; + + if (s_ts < l_ts) { + v4l2_err(&dev->v4l2_dev, + "s/l frame err, timestamp s:%lld l:%lld\n", + s_ts, l_ts); + goto RDBK_TOISP_UNMATCH; + } + + if ((s_ts - l_ts) > time) { + ret = v4l2_subdev_call(sensor->sd, + video, + g_frame_interval, + &sensor->fi); + if (!ret) { + denominator = sensor->fi.interval.denominator; + numerator = sensor->fi.interval.numerator; + if (denominator && numerator) { + time = numerator * 1000 / denominator * 1000 * 1000; + fps = denominator / numerator; + } + } + if ((s_ts - l_ts) > time) { + v4l2_err(&dev->v4l2_dev, + "timestamp no match, s:%lld l:%lld, fps:%d\n", + s_ts, l_ts, fps); + goto RDBK_TOISP_UNMATCH; + } + } + dev->rdbk_rx_buf[RDBK_M]->dbufs.sequence = dev->rdbk_rx_buf[RDBK_L]->dbufs.sequence; + rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_L]->dbufs); + rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_M]->dbufs); + rkcif_rdbk_with_tools(&dev->stream[RDBK_L], dev->rdbk_rx_buf[RDBK_L]); + rkcif_rdbk_with_tools(&dev->stream[RDBK_M], dev->rdbk_rx_buf[RDBK_M]); + atomic_dec(&dev->stream[RDBK_L].buf_cnt); + atomic_dec(&dev->stream[RDBK_M].buf_cnt); + dev->rdbk_rx_buf[RDBK_L] = NULL; + dev->rdbk_rx_buf[RDBK_M] = NULL; + } + + spin_unlock_irqrestore(&dev->hdr_lock, flags); + return; + +RDBK_TOISP_UNMATCH: + spin_unlock_irqrestore(&dev->hdr_lock, flags); +} + +static void rkcif_write_buff_addr_multi_dev_combine(struct rkcif_stream *stream, + u32 frm_addr_y, u32 frm_addr_uv, + u32 buff_addr_y, u32 buff_addr_cbcr, + bool is_dummy_buf) +{ + struct rkcif_device *dev = stream->cifdev; + struct rkmodule_capture_info *capture_info = &dev->channels[stream->id].capture_info; + u32 addr_y, addr_cbcr; + int addr_offset = 0; + int i = 0; + int tmp_host_index = dev->csi_host_idx; + + for (i = 0; i < capture_info->multi_dev.dev_num; i++) { + if (is_dummy_buf) { + addr_y = buff_addr_y; + } else { + addr_offset = dev->channels[stream->id].left_virtual_width; + addr_y = buff_addr_y + addr_offset * i; + } + dev->csi_host_idx = capture_info->multi_dev.dev_idx[i]; + rkcif_write_register(dev, frm_addr_y, addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW && + frm_addr_uv && buff_addr_cbcr) { + if (is_dummy_buf) { + addr_cbcr = buff_addr_cbcr; + } else { + addr_offset = dev->channels[stream->id].left_virtual_width; + addr_cbcr = buff_addr_cbcr + addr_offset * i; + } + rkcif_write_register(dev, frm_addr_uv, addr_cbcr); + } + } + dev->csi_host_idx = tmp_host_index; +} + +static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, + int channel_id) +{ + struct rkcif_device *dev = stream->cifdev; + struct rkcif_rx_buffer *rx_buf; + struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + struct rkmodule_capture_info *capture_info = &dev->channels[channel_id].capture_info; + u32 frm0_addr_y; + u32 frm1_addr_y; + u32 buff_addr_y; + unsigned long flags; + + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm0_addr_y = get_reg_index_of_frm0_y_addr(channel_id); + frm1_addr_y = get_reg_index_of_frm1_y_addr(channel_id); + } else { + frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(channel_id); + frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(channel_id); + } + + spin_lock_irqsave(&stream->vbq_lock, flags); + + if (!stream->curr_buf_toisp) { + if (!list_empty(&stream->rx_buf_head)) { + rx_buf = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, + list); + if (rx_buf) { + list_del(&rx_buf->list); + stream->curr_buf_toisp = rx_buf; + } + } + } + + if (stream->curr_buf_toisp) { + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm0_addr_y, 0, + buff_addr_y, 0, false); + } else { + rkcif_write_register(dev, frm0_addr_y, buff_addr_y); + } + } + + if (!stream->next_buf_toisp) { + if (!list_empty(&stream->rx_buf_head)) { + rx_buf = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); + if (rx_buf) { + list_del(&rx_buf->list); + stream->next_buf_toisp = rx_buf; + } else { + stream->next_buf_toisp = stream->curr_buf_toisp; + } + } else { + stream->next_buf_toisp = stream->curr_buf_toisp; + } + } + + if (stream->next_buf_toisp) { + buff_addr_y = stream->next_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm1_addr_y, 0, + buff_addr_y, 0, false); + } else { + rkcif_write_register(dev, frm1_addr_y, buff_addr_y); + } + } + + spin_unlock_irqrestore(&stream->vbq_lock, flags); + stream->buf_owner = RKCIF_DMAEN_BY_ISP; +} + +static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, + int channel_id) +{ + struct rkcif_device *dev = stream->cifdev; + struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + struct rkmodule_capture_info *capture_info = &dev->channels[channel_id].capture_info; + struct rkcif_rx_buffer *buffer = NULL; + struct rkcif_rx_buffer *active_buf = NULL; + struct sditf_priv *priv = dev->sditf[0]; + u32 frm_addr_y, buff_addr_y; + unsigned long flags; + + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_reg_index_of_frm0_y_addr(channel_id) : + get_reg_index_of_frm1_y_addr(channel_id); + } else { + frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_dvp_reg_index_of_frm0_y_addr(channel_id) : + get_dvp_reg_index_of_frm1_y_addr(channel_id); + } + spin_lock_irqsave(&stream->vbq_lock, flags); + if (!list_empty(&stream->rx_buf_head)) { + if (stream->frame_phase == CIF_CSI_FRAME0_READY) { + if (stream->curr_buf_toisp == stream->next_buf_toisp) + active_buf = NULL; + else + active_buf = stream->curr_buf_toisp; + + buffer = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); + if (buffer) { + list_del(&buffer->list); + stream->curr_buf_toisp = buffer; + } + if (priv && priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) { + if (!active_buf) + goto out_get_buf; + if (stream->frame_idx == 1) + active_buf->dbufs.is_first = true; + active_buf->dbufs.sequence = stream->frame_idx - 1; + active_buf->dbufs.timestamp = stream->readout.fs_timestamp; + active_buf->fe_timestamp = ktime_get_ns(); + stream->last_frame_idx = stream->frame_idx; + if (dev->hdr.hdr_mode == NO_HDR) { + rkcif_s_rx_buffer(dev, &active_buf->dbufs); + if (dev->is_support_tools && stream->tools_vdev) + rkcif_rdbk_with_tools(stream, active_buf); + atomic_dec(&stream->buf_cnt); + } else { + rkcif_rdbk_frame_end_toisp(stream, active_buf); + } + } else { + rkcif_s_rx_buffer(dev, &active_buf->dbufs); + if (dev->is_support_tools && stream->tools_vdev) + rkcif_rdbk_with_tools(stream, active_buf); + } + } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { + if (stream->curr_buf_toisp == stream->next_buf_toisp) + active_buf = NULL; + else + active_buf = stream->next_buf_toisp; + buffer = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); + if (buffer) { + list_del(&buffer->list); + stream->next_buf_toisp = buffer; + } + if (priv && priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) { + if (!active_buf) + goto out_get_buf; + if (stream->frame_idx == 1) + active_buf->dbufs.is_first = true; + active_buf->dbufs.sequence = stream->frame_idx - 1; + active_buf->dbufs.timestamp = stream->readout.fs_timestamp; + active_buf->fe_timestamp = ktime_get_ns(); + stream->last_frame_idx = stream->frame_idx; + if (dev->hdr.hdr_mode == NO_HDR) { + rkcif_s_rx_buffer(dev, &active_buf->dbufs); + if (dev->is_support_tools && stream->tools_vdev) + rkcif_rdbk_with_tools(stream, active_buf); + atomic_dec(&stream->buf_cnt); + } else { + rkcif_rdbk_frame_end_toisp(stream, active_buf); + } + } else { + rkcif_s_rx_buffer(dev, &active_buf->dbufs); + if (dev->is_support_tools && stream->tools_vdev) + rkcif_rdbk_with_tools(stream, active_buf); + } + } + if (stream->lack_buf_cnt) + stream->lack_buf_cnt--; + } else { + if (priv->mode.rdbk_mode == RKISP_VICAP_ONLINE) + goto out_get_buf; + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + if (dev->hw_dev->dummy_buf.vaddr) { + if (stream->frame_phase == CIF_CSI_FRAME0_READY) { + active_buf = stream->curr_buf_toisp; + stream->curr_buf_toisp = NULL; + } else { + active_buf = stream->next_buf_toisp; + stream->next_buf_toisp = NULL; + } + } else if (stream->curr_buf_toisp && stream->next_buf_toisp && + stream->curr_buf_toisp != stream->next_buf_toisp) { + if (stream->frame_phase == CIF_CSI_FRAME0_READY) { + active_buf = stream->curr_buf_toisp; + stream->curr_buf_toisp = stream->next_buf_toisp; + buffer = stream->next_buf_toisp; + } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { + active_buf = stream->next_buf_toisp; + stream->next_buf_toisp = stream->curr_buf_toisp; + buffer = stream->curr_buf_toisp; + } + if (stream->cifdev->rdbk_debug) + v4l2_info(&stream->cifdev->v4l2_dev, + "stream[%d] hold buf %x\n", + stream->id, + (u32)stream->next_buf_toisp->dummy.dma_addr); + } + if (active_buf) { + if (stream->frame_idx == 1) + active_buf->dbufs.is_first = true; + active_buf->dbufs.sequence = stream->frame_idx - 1; + active_buf->dbufs.timestamp = stream->readout.fs_timestamp; + active_buf->fe_timestamp = ktime_get_ns(); + stream->last_frame_idx = stream->frame_idx; + if (dev->hdr.hdr_mode == NO_HDR) { + rkcif_s_rx_buffer(dev, &active_buf->dbufs); + if (dev->is_support_tools && stream->tools_vdev) + rkcif_rdbk_with_tools(stream, active_buf); + atomic_dec(&stream->buf_cnt); + } else { + rkcif_rdbk_frame_end_toisp(stream, active_buf); + } + } else { + if (stream->cifdev->rdbk_debug && dev->hw_dev->dummy_buf.vaddr) + v4l2_info(&stream->cifdev->v4l2_dev, + "stream[%d] loss frame %d\n", + stream->id, + stream->frame_idx - 1); + } + if (dev->is_support_tools && stream->tools_vdev && stream->curr_buf_toisp) + rkcif_rdbk_with_tools(stream, stream->curr_buf_toisp); + } + +out_get_buf: + stream->frame_phase_cache = stream->frame_phase; + if (buffer) { + buff_addr_y = buffer->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, 0, + buff_addr_y, 0, false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } + if (dev->rdbk_debug > 1 && + stream->frame_idx < 15) + v4l2_info(&dev->v4l2_dev, + "stream[%d] update, seq %d, reg %x, buf %x\n", + stream->id, + stream->frame_idx - 1, + frm_addr_y, (u32)buffer->dummy.dma_addr); + } else if (dev->hw_dev->dummy_buf.vaddr && priv && + priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) { + buff_addr_y = dev->hw_dev->dummy_buf.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, 0, + buff_addr_y, 0, true); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); + return 0; +} + +static int rkcif_assign_new_buffer_pingpong_toisp(struct rkcif_stream *stream, + int init, int channel_id) +{ + int ret = 0; + + if (init) + rkcif_assign_new_buffer_init_toisp(stream, channel_id); + else + ret = rkcif_assign_new_buffer_update_toisp(stream, channel_id); + return ret; +} + +void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) +{ + struct rkcif_device *dev = stream->cifdev; + struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + struct rkcif_rx_buffer *buffer = NULL; + struct rkmodule_capture_info *capture_info = &dev->channels[stream->id].capture_info; + struct rkcif_rx_buffer *active_buf = NULL; + u32 frm_addr_y, buff_addr_y; + u32 vblank = 0; + u32 vblank_ns = 0; + u64 cur_time = 0; + int frame_phase = 0; + int frame_phase_next = 0; + bool is_early_update = false; + + if (stream->curr_buf_toisp != stream->next_buf_toisp) { + if (dev->rdbk_debug > 2 && + stream->frame_idx < 15) + v4l2_info(&dev->v4l2_dev, + "stream[%d] addr check not equal 0x%x 0x%x\n", + stream->id, + (u32)stream->curr_buf_toisp->dummy.dma_addr, + (u32)stream->next_buf_toisp->dummy.dma_addr); + return; + } + if (!dev->sensor_linetime) + dev->sensor_linetime = rkcif_get_linetime(stream); + vblank = rkcif_get_sensor_vblank(dev); + vblank_ns = vblank * dev->sensor_linetime; + cur_time = ktime_get_ns(); + + if (dev->chip_id > CHIP_RK3568_CIF && + dev->hdr.hdr_mode == NO_HDR && + cur_time - stream->readout.fe_timestamp < (vblank_ns - 500000) && + stream->lack_buf_cnt == 2 && + stream->frame_idx > stream->last_frame_idx) { + is_early_update = true; + frame_phase = stream->frame_phase & CIF_CSI_FRAME0_READY ? + CIF_CSI_FRAME1_READY : CIF_CSI_FRAME0_READY; + frame_phase_next = stream->frame_phase & CIF_CSI_FRAME0_READY ? + CIF_CSI_FRAME0_READY : CIF_CSI_FRAME1_READY; + } else { + frame_phase = stream->frame_phase; + } + if (dev->rdbk_debug > 2 && + stream->frame_idx < 15) + v4l2_info(&dev->v4l2_dev, + "stream[%d] check update, cur %lld, fe %lld, vb %u lack_buf %d\n", + stream->id, + cur_time, stream->readout.fe_timestamp, + vblank_ns, stream->lack_buf_cnt); + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm_addr_y = frame_phase & CIF_CSI_FRAME0_READY ? + get_reg_index_of_frm0_y_addr(stream->id) : + get_reg_index_of_frm1_y_addr(stream->id); + } else { + frm_addr_y = frame_phase & CIF_CSI_FRAME0_READY ? + get_dvp_reg_index_of_frm0_y_addr(stream->id) : + get_dvp_reg_index_of_frm1_y_addr(stream->id); + } + if (!list_empty(&stream->rx_buf_head)) { + if (frame_phase == CIF_CSI_FRAME0_READY) { + active_buf = stream->curr_buf_toisp; + buffer = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); + if (buffer) { + list_del(&buffer->list); + stream->curr_buf_toisp = buffer; + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, 0, + buff_addr_y, 0, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } + if (dev->rdbk_debug > 1 && + stream->frame_idx < 15) + v4l2_info(&dev->v4l2_dev, + "stream[%d] check update, seq %d, addr 0x%x, buf 0x%x\n", + stream->id, + stream->frame_idx - 1, frm_addr_y, + (u32)stream->curr_buf_toisp->dummy.dma_addr); + } + } else if (frame_phase == CIF_CSI_FRAME1_READY) { + active_buf = stream->next_buf_toisp; + buffer = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); + if (buffer) { + list_del(&buffer->list); + stream->next_buf_toisp = buffer; + buff_addr_y = stream->next_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, 0, + buff_addr_y, 0, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } + if (dev->rdbk_debug > 1 && + stream->frame_idx < 15) + v4l2_info(&dev->v4l2_dev, + "stream[%d] check update, seq %d, addr 0x%x, buf 0x%x\n", + stream->id, + stream->frame_idx - 1, frm_addr_y, + (u32)stream->next_buf_toisp->dummy.dma_addr); + } + } + if (stream->lack_buf_cnt) + stream->lack_buf_cnt--; + } + if (is_early_update) { + if (dev->rdbk_debug > 1 && + stream->frame_idx < 15) + v4l2_info(&dev->v4l2_dev, + "stream[%d] early update, seq %d\n", + stream->id, + stream->frame_idx - 1); + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY) + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_CTRL, 0x00010000); + else + rkcif_write_register_or(dev, CIF_REG_DVP_CTRL, 0x00010000); + if (active_buf) { + active_buf->dbufs.sequence = stream->frame_idx - 1; + active_buf->dbufs.timestamp = stream->readout.fs_timestamp; + stream->last_frame_idx = stream->frame_idx; + rkcif_s_rx_buffer(dev, &active_buf->dbufs); + } + if (dev->hw_dev->dummy_buf.vaddr) + return; + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm_addr_y = frame_phase_next & CIF_CSI_FRAME0_READY ? + get_reg_index_of_frm0_y_addr(stream->id) : + get_reg_index_of_frm1_y_addr(stream->id); + } else { + frm_addr_y = frame_phase_next & CIF_CSI_FRAME0_READY ? + get_dvp_reg_index_of_frm0_y_addr(stream->id) : + get_dvp_reg_index_of_frm1_y_addr(stream->id); + } + if (frame_phase == CIF_CSI_FRAME0_READY) + stream->next_buf_toisp = stream->curr_buf_toisp; + else + stream->curr_buf_toisp = stream->next_buf_toisp; + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, 0, + buff_addr_y, 0, false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } + } } static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, @@ -1288,11 +2299,13 @@ struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; u32 frm0_addr_y, frm0_addr_uv; u32 frm1_addr_y, frm1_addr_uv; + u32 buff_addr_y, buff_addr_cbcr; unsigned long flags; - struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; struct csi_channel_info *channel = &dev->channels[channel_id]; - if (mbus_cfg->type == V4L2_MBUS_CSI2 || + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || mbus_cfg->type == V4L2_MBUS_CCP2) { frm0_addr_y = get_reg_index_of_frm0_y_addr(channel_id); frm0_addr_uv = get_reg_index_of_frm0_uv_addr(channel_id); @@ -1312,53 +2325,117 @@ stream->curr_buf = list_first_entry(&stream->buf_head, struct rkcif_buffer, queue); + v4l2_dbg(4, rkcif_debug, &dev->v4l2_dev, "%s %d, stream[%d] buf idx %d\n", + __func__, __LINE__, stream->id, stream->curr_buf->vb.vb2_buf.index); list_del(&stream->curr_buf->queue); } } if (stream->curr_buf) { - rkcif_write_register(dev, frm0_addr_y, - stream->curr_buf->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm0_addr_uv, - stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]); + buff_addr_y = stream->curr_buf->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm0_addr_y, + frm0_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm0_addr_y, + stream->curr_buf->buff_addr[RKCIF_PLANE_Y]); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm0_addr_uv, + stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]); + } } else { if (dummy_buf->vaddr) { - rkcif_write_register(dev, frm0_addr_y, dummy_buf->dma_addr); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm0_addr_uv, dummy_buf->dma_addr); + buff_addr_y = dummy_buf->dma_addr; + buff_addr_cbcr = dummy_buf->dma_addr; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm0_addr_y, + frm0_addr_uv, + buff_addr_y, + buff_addr_cbcr, + true); + } else { + rkcif_write_register(dev, frm0_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm0_addr_uv, buff_addr_cbcr); + } + } else { + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; } } if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { stream->next_buf = stream->curr_buf; if (stream->next_buf) { - rkcif_write_register(dev, frm1_addr_y, - stream->next_buf->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2)); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm1_addr_uv, - stream->next_buf->buff_addr[RKCIF_PLANE_CBCR] + (channel->virtual_width / 2)); + buff_addr_y = stream->next_buf->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm1_addr_y, + frm1_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm1_addr_y, + buff_addr_y + (channel->virtual_width / 2)); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, + buff_addr_cbcr + (channel->virtual_width / 2)); + } } } else { if (!stream->next_buf) { if (!list_empty(&stream->buf_head)) { stream->next_buf = list_first_entry(&stream->buf_head, struct rkcif_buffer, queue); + v4l2_dbg(4, rkcif_debug, &dev->v4l2_dev, "%s %d, stream[%d] buf idx %d\n", + __func__, __LINE__, stream->id, stream->next_buf->vb.vb2_buf.index); list_del(&stream->next_buf->queue); } } - if (stream->next_buf) { - rkcif_write_register(dev, frm1_addr_y, - stream->next_buf->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm1_addr_uv, - stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]); - } else { - if (dummy_buf->vaddr) { + if (!stream->next_buf && dummy_buf->vaddr) { + buff_addr_y = dummy_buf->dma_addr; + buff_addr_cbcr = dummy_buf->dma_addr; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm1_addr_y, + frm1_addr_uv, + buff_addr_y, + buff_addr_cbcr, + true); + } else { rkcif_write_register(dev, frm1_addr_y, dummy_buf->dma_addr); if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) rkcif_write_register(dev, frm1_addr_uv, dummy_buf->dma_addr); + } + + } else if (!stream->next_buf && stream->curr_buf) { + stream->next_buf = stream->curr_buf; + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + } + if (stream->next_buf) { + buff_addr_y = stream->next_buf->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm1_addr_y, + frm1_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm1_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, buff_addr_cbcr); } } } @@ -1391,22 +2468,26 @@ } } } - + stream->buf_owner = RKCIF_DMAEN_BY_VICAP; } static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, - int channel_id) + int channel_id) { struct rkcif_device *dev = stream->cifdev; - struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; struct rkcif_buffer *buffer = NULL; u32 frm_addr_y, frm_addr_uv; struct csi_channel_info *channel = &dev->channels[channel_id]; + struct rkisp_rx_buf *dbufs = NULL; + struct dma_buf *dbuf = NULL; int ret = 0; + u32 buff_addr_y, buff_addr_cbcr; unsigned long flags; - if (mbus_cfg->type == V4L2_MBUS_CSI2 || + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || mbus_cfg->type == V4L2_MBUS_CCP2) { frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? get_reg_index_of_frm0_y_addr(channel_id) : @@ -1423,20 +2504,43 @@ get_dvp_reg_index_of_frm1_uv_addr(channel_id); } + if (stream->to_stop_dma) { + if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "%s %d\n", __func__, __LINE__); + goto stop_dma; + } else { + if (stream->frame_phase == CIF_CSI_FRAME0_READY) + stream->curr_buf = NULL; + else + stream->next_buf = NULL; + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "%s %d\n", __func__, __LINE__); + return -EINVAL; + } + } + spin_lock_irqsave(&stream->vbq_lock, flags); if (!list_empty(&stream->buf_head)) { + if (!dummy_buf->vaddr && stream->curr_buf == stream->next_buf && stream->cif_fmt_in->field != V4L2_FIELD_INTERLACED) ret = -EINVAL; + if (stream->frame_phase == CIF_CSI_FRAME0_READY) { + if (!stream->curr_buf) + ret = -EINVAL; stream->curr_buf = list_first_entry(&stream->buf_head, struct rkcif_buffer, queue); if (stream->curr_buf) { list_del(&stream->curr_buf->queue); buffer = stream->curr_buf; + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, + "stream[%d] update curr_buf 0x%x, buf idx %d\n", + stream->id, buffer->buff_addr[0], stream->curr_buf->vb.vb2_buf.index); } } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { + if (!stream->next_buf) + ret = -EINVAL; if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { if (stream->next_buf != stream->curr_buf) { stream->next_buf = stream->curr_buf; @@ -1451,14 +2555,17 @@ if (stream->next_buf) { list_del(&stream->next_buf->queue); buffer = stream->next_buf; + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, + "stream[%d] update next_buf 0x%x, buf idx %d\n", + stream->id, buffer->buff_addr[0], stream->next_buf->vb.vb2_buf.index); } } } - } else { + } else if (!(stream->dma_en & RKCIF_DMAEN_BY_ISP)) { buffer = NULL; if (dummy_buf->vaddr) { if (stream->frame_phase == CIF_CSI_FRAME0_READY) { - stream->curr_buf = NULL; + stream->curr_buf = NULL; } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { stream->next_buf = stream->curr_buf; @@ -1467,7 +2574,8 @@ stream->next_buf = NULL; } } - } else if (stream->curr_buf != stream->next_buf) { + } else if (stream->curr_buf && stream->next_buf && + stream->curr_buf != stream->next_buf) { if (stream->frame_phase == CIF_CSI_FRAME0_READY) { stream->curr_buf = stream->next_buf; buffer = stream->next_buf; @@ -1475,49 +2583,175 @@ stream->next_buf = stream->curr_buf; buffer = stream->curr_buf; } - + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + } else { + stream->curr_buf = NULL; + stream->next_buf = NULL; + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; } - } stream->frame_phase_cache = stream->frame_phase; - spin_unlock_irqrestore(&stream->vbq_lock, flags); if (buffer) { + buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR]; if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED && stream->frame_phase == CIF_CSI_FRAME1_READY) { - rkcif_write_register(dev, frm_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2)); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR] + (channel->virtual_width / 2)); + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm_addr_y, + buff_addr_y + (channel->virtual_width / 2)); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, + buff_addr_cbcr + (channel->virtual_width / 2)); + } } else { - rkcif_write_register(dev, frm_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR]); + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, buff_addr_cbcr); + } + } + if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { + if (stream->buf_replace_cnt < 2) + stream->buf_replace_cnt++; + if (stream->frame_phase == CIF_CSI_FRAME0_READY && + stream->next_buf) + dbuf = stream->next_buf->dbuf; + else if (stream->frame_phase == CIF_CSI_FRAME1_READY && + stream->curr_buf) + dbuf = stream->curr_buf->dbuf; + + if (dbuf) { + list_for_each_entry(dbufs, &stream->rx_buf_head_vicap, list) { + if (dbufs->dbuf == dbuf) + break; + } + } + if (dbufs) + rkcif_s_rx_buffer(dev, dbufs); } } else { - if (dummy_buf->vaddr) { - rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr); + if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, 0, + buff_addr_y, 0, false); + else + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + if (stream->frame_phase == CIF_CSI_FRAME0_READY && + stream->next_buf) + dbuf = stream->next_buf->dbuf; + else if (stream->frame_phase == CIF_CSI_FRAME1_READY && + stream->curr_buf) + dbuf = stream->curr_buf->dbuf; + + if (dbuf) { + list_for_each_entry(dbufs, &stream->rx_buf_head_vicap, list) + if (dbufs->dbuf == dbuf) + break; + } else { + dbufs = &stream->curr_buf_toisp->dbufs; + } + rkcif_s_rx_buffer(dev, dbufs); + if (stream->curr_buf && stream->frame_phase == CIF_CSI_FRAME0_READY) { + stream->curr_buf = NULL; + if (stream->buf_replace_cnt) + stream->buf_replace_cnt--; + } else if (stream->next_buf && stream->frame_phase == CIF_CSI_FRAME1_READY) { + stream->next_buf = NULL; + if (stream->buf_replace_cnt) + stream->buf_replace_cnt--; + } + } else if (dummy_buf->vaddr) { + + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + buff_addr_y = dummy_buf->dma_addr; + buff_addr_cbcr = dummy_buf->dma_addr; + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + true); + } else { + rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr); + } + dev->err_state |= (RKCIF_ERR_ID0_NOT_BUF << stream->id); + dev->irq_stats.not_active_buf_cnt[stream->id]++; + } else { ret = -EINVAL; + stream->curr_buf = NULL; + stream->next_buf = NULL; + dev->err_state |= (RKCIF_ERR_ID0_NOT_BUF << stream->id); + dev->irq_stats.not_active_buf_cnt[stream->id]++; } - v4l2_info(&dev->v4l2_dev, - "not active buffer, skip current frame, %s stream[%d]\n", - (mbus_cfg->type == V4L2_MBUS_CSI2 || - mbus_cfg->type == V4L2_MBUS_CCP2) ? "mipi/lvds" : "dvp", - stream->id); } + spin_unlock_irqrestore(&stream->vbq_lock, flags); return ret; +stop_dma: + if (stream->buf_replace_cnt) { + spin_lock_irqsave(&stream->vbq_lock, flags); + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, 0, + buff_addr_y, 0, false); + else + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + if (stream->frame_phase == CIF_CSI_FRAME0_READY && + stream->next_buf) + dbuf = stream->next_buf->dbuf; + else if (stream->frame_phase == CIF_CSI_FRAME1_READY && + stream->curr_buf) + dbuf = stream->curr_buf->dbuf; + + if (dbuf) { + list_for_each_entry(dbufs, &stream->rx_buf_head_vicap, list) + if (dbufs->dbuf == dbuf) + break; + } else { + dbufs = &stream->curr_buf_toisp->dbufs; + } + if (dbufs) + rkcif_s_rx_buffer(dev, dbufs); + + if (stream->frame_phase == CIF_CSI_FRAME0_READY && + stream->curr_buf) { + stream->curr_buf = NULL; + } else if (stream->frame_phase == CIF_CSI_FRAME1_READY && + stream->next_buf) { + stream->next_buf = NULL; + } + stream->buf_replace_cnt--; + spin_unlock_irqrestore(&stream->vbq_lock, flags); + } + return -EINVAL; } static int rkcif_get_new_buffer_wake_up_mode(struct rkcif_stream *stream) { struct rkcif_device *dev = stream->cifdev; - struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; int ret = 0; unsigned long flags; @@ -1538,6 +2772,8 @@ list_del(&stream->next_buf->queue); } stream->is_buf_active = true; + if (stream->lack_buf_cnt) + stream->lack_buf_cnt--; } else { stream->is_buf_active = false; if (dummy_buf->vaddr) { @@ -1554,8 +2790,15 @@ stream->frame_phase_cache = CIF_CSI_FRAME1_READY; } stream->is_buf_active = true; + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; } else { - ret = -EINVAL; + if (dev->chip_id < CHIP_RK3588_CIF) + ret = -EINVAL; + else + ret = 0; + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; } } spin_unlock_irqrestore(&stream->vbq_lock, flags); @@ -1566,15 +2809,18 @@ static int rkcif_update_new_buffer_wake_up_mode(struct rkcif_stream *stream) { struct rkcif_device *dev = stream->cifdev; - struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + struct rkmodule_capture_info *capture_info = &dev->channels[stream->id].capture_info; struct rkcif_buffer *buffer = NULL; u32 frm_addr_y, frm_addr_uv; + u32 buff_addr_y, buff_addr_cbcr; int channel_id = stream->id; int ret = 0; unsigned long flags; - if (mbus_cfg->type == V4L2_MBUS_CSI2 || + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || mbus_cfg->type == V4L2_MBUS_CCP2) { frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? get_reg_index_of_frm0_y_addr(channel_id) : @@ -1599,25 +2845,122 @@ } spin_unlock_irqrestore(&stream->vbq_lock, flags); if (buffer) { - rkcif_write_register(dev, frm_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR]); + buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR]; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, buff_addr_cbcr); + } } else { if (dummy_buf->vaddr) { - rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr); + buff_addr_y = dummy_buf->dma_addr; + buff_addr_cbcr = dummy_buf->dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + true); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, buff_addr_cbcr); + } + } else { + if (dev->chip_id < CHIP_RK3588_CIF) + ret = -EINVAL; + else + ret = 0; + } + dev->err_state |= (RKCIF_ERR_ID0_NOT_BUF << stream->id); + dev->irq_stats.not_active_buf_cnt[stream->id]++; + } + + return ret; +} + +static int rkcif_get_new_buffer_wake_up_mode_rdbk(struct rkcif_stream *stream) +{ + struct rkcif_rx_buffer *buffer = NULL; + struct rkcif_device *dev = stream->cifdev; + struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + int ret = 0; + unsigned long flags; + u32 frm_addr_y; + int frame_phase = 0; + + spin_lock_irqsave(&stream->vbq_lock, flags); + if (!list_empty(&stream->rx_buf_head)) { + if (stream->line_int_cnt % 2) { + buffer = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); + if (buffer) { + list_del(&buffer->list); + stream->curr_buf_toisp = buffer; + } + frame_phase = CIF_CSI_FRAME0_READY; + } else { + buffer = list_first_entry(&stream->rx_buf_head, + struct rkcif_rx_buffer, list); + if (buffer) { + list_del(&buffer->list); + stream->next_buf_toisp = buffer; + } + frame_phase = CIF_CSI_FRAME1_READY; + } + if (stream->lack_buf_cnt) + stream->lack_buf_cnt--; + } else { + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + if (stream->curr_buf_toisp && stream->next_buf_toisp && + stream->curr_buf_toisp != stream->next_buf_toisp) { + if (stream->line_int_cnt % 2) + stream->curr_buf_toisp = stream->next_buf_toisp; + else + stream->next_buf_toisp = stream->curr_buf_toisp; + buffer = stream->curr_buf_toisp; + ret = 0; + if (stream->cifdev->rdbk_debug) + v4l2_info(&stream->cifdev->v4l2_dev, + "stream[%d] hold buf %x\n", + stream->id, + (u32)stream->next_buf_toisp->dummy.dma_addr); } else { ret = -EINVAL; } - v4l2_info(&dev->v4l2_dev, - "not active buffer, skip current frame, %s stream[%d]\n", - (mbus_cfg->type == V4L2_MBUS_CSI2 || - mbus_cfg->type == V4L2_MBUS_CCP2) ? "mipi/lvds" : "dvp", - stream->id); } + if (buffer) { + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm_addr_y = frame_phase & CIF_CSI_FRAME0_READY ? + get_reg_index_of_frm0_y_addr(stream->id) : + get_reg_index_of_frm1_y_addr(stream->id); + } else { + frm_addr_y = frame_phase & CIF_CSI_FRAME0_READY ? + get_dvp_reg_index_of_frm0_y_addr(stream->id) : + get_dvp_reg_index_of_frm1_y_addr(stream->id); + } + rkcif_write_register(dev, frm_addr_y, + buffer->dummy.dma_addr); + if (dev->rdbk_debug > 1 && + stream->frame_idx < 15) + v4l2_info(&dev->v4l2_dev, + "stream[%d] rdbk update, seq %d, reg %x, buf %x\n", + stream->id, + stream->frame_idx - 1, + frm_addr_y, (u32)buffer->dummy.dma_addr); + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); return ret; } @@ -1626,7 +2969,7 @@ { struct rkcif_device *dev = stream->cifdev; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; - struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; unsigned long flags; spin_lock_irqsave(&stream->vbq_lock, flags); @@ -1661,6 +3004,276 @@ rkcif_assign_new_buffer_init(stream, channel_id); else ret = rkcif_assign_new_buffer_update(stream, channel_id); + return ret; +} + +static void rkcif_assign_new_buffer_init_rockit(struct rkcif_stream *stream, + int channel_id) +{ + struct rkcif_device *dev = stream->cifdev; + struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + u32 frm0_addr_y, frm0_addr_uv; + u32 frm1_addr_y, frm1_addr_uv; + unsigned long flags; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; + struct csi_channel_info *channel = &dev->channels[channel_id]; + + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm0_addr_y = get_reg_index_of_frm0_y_addr(channel_id); + frm0_addr_uv = get_reg_index_of_frm0_uv_addr(channel_id); + frm1_addr_y = get_reg_index_of_frm1_y_addr(channel_id); + frm1_addr_uv = get_reg_index_of_frm1_uv_addr(channel_id); + } else { + frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(channel_id); + frm0_addr_uv = get_dvp_reg_index_of_frm0_uv_addr(channel_id); + frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(channel_id); + frm1_addr_uv = get_dvp_reg_index_of_frm1_uv_addr(channel_id); + } + + spin_lock_irqsave(&stream->vbq_lock, flags); + + if (!stream->curr_buf_rockit) { + if (!list_empty(&stream->rockit_buf_head)) { + stream->curr_buf_rockit = list_first_entry(&stream->rockit_buf_head, + struct rkcif_buffer, + queue); + list_del(&stream->curr_buf_rockit->queue); + } + } + + if (stream->curr_buf_rockit) { + rkcif_write_register(dev, frm0_addr_y, + stream->curr_buf_rockit->buff_addr[RKCIF_PLANE_Y]); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm0_addr_uv, + stream->curr_buf_rockit->buff_addr[RKCIF_PLANE_CBCR]); + } else { + if (dummy_buf->vaddr) { + rkcif_write_register(dev, frm0_addr_y, dummy_buf->dma_addr); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm0_addr_uv, dummy_buf->dma_addr); + } else { + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + } + } + + if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { + stream->next_buf_rockit = stream->curr_buf_rockit; + if (stream->next_buf_rockit) { + rkcif_write_register(dev, frm1_addr_y, + stream->next_buf_rockit->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2)); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, + stream->next_buf_rockit->buff_addr[RKCIF_PLANE_CBCR] + (channel->virtual_width / 2)); + } + } else { + if (!stream->next_buf_rockit) { + if (!list_empty(&stream->rockit_buf_head)) { + stream->next_buf_rockit = list_first_entry(&stream->rockit_buf_head, + struct rkcif_buffer, queue); + list_del(&stream->next_buf_rockit->queue); + } + } + + if (stream->next_buf_rockit) { + rkcif_write_register(dev, frm1_addr_y, + stream->next_buf_rockit->buff_addr[RKCIF_PLANE_Y]); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, + stream->next_buf_rockit->buff_addr[RKCIF_PLANE_CBCR]); + } else { + if (dummy_buf->vaddr) { + rkcif_write_register(dev, frm1_addr_y, dummy_buf->dma_addr); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, dummy_buf->dma_addr); + } else { + if (stream->curr_buf_rockit) { + stream->next_buf_rockit = stream->curr_buf_rockit; + rkcif_write_register(dev, frm1_addr_y, + stream->next_buf_rockit->buff_addr[RKCIF_PLANE_Y]); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, + stream->next_buf_rockit->buff_addr[RKCIF_PLANE_CBCR]); + } + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + } + } + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); + + stream->is_dvp_yuv_addr_init = true; + + /* for BT.656/BT.1120 multi channels function, + * yuv addr of unused channel must be set + */ + if (mbus_cfg->type == V4L2_MBUS_BT656) { + int ch_id; + + for (ch_id = 0; ch_id < RKCIF_MAX_STREAM_DVP; ch_id++) { + if (dev->stream[ch_id].is_dvp_yuv_addr_init) + continue; + if (dummy_buf->dma_addr) { + rkcif_write_register(dev, + get_dvp_reg_index_of_frm0_y_addr(ch_id), + dummy_buf->dma_addr); + rkcif_write_register(dev, + get_dvp_reg_index_of_frm0_uv_addr(ch_id), + dummy_buf->dma_addr); + rkcif_write_register(dev, + get_dvp_reg_index_of_frm1_y_addr(ch_id), + dummy_buf->dma_addr); + rkcif_write_register(dev, + get_dvp_reg_index_of_frm1_uv_addr(ch_id), + dummy_buf->dma_addr); + } + } + } + stream->buf_owner = RKCIF_DMAEN_BY_ROCKIT; +} + +static int rkcif_assign_new_buffer_update_rockit(struct rkcif_stream *stream, + int channel_id) +{ + struct rkcif_device *dev = stream->cifdev; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; + struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + struct rkcif_buffer *buffer = NULL; + u32 frm_addr_y, frm_addr_uv; + struct csi_channel_info *channel = &dev->channels[channel_id]; + int ret = 0; + unsigned long flags; + + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_reg_index_of_frm0_y_addr(channel_id) : + get_reg_index_of_frm1_y_addr(channel_id); + frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_reg_index_of_frm0_uv_addr(channel_id) : + get_reg_index_of_frm1_uv_addr(channel_id); + } else { + frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_dvp_reg_index_of_frm0_y_addr(channel_id) : + get_dvp_reg_index_of_frm1_y_addr(channel_id); + frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_dvp_reg_index_of_frm0_uv_addr(channel_id) : + get_dvp_reg_index_of_frm1_uv_addr(channel_id); + } + + spin_lock_irqsave(&stream->vbq_lock, flags); + if (!list_empty(&stream->rockit_buf_head)) { + + if (!dummy_buf->vaddr && + stream->curr_buf_rockit == stream->next_buf_rockit && + stream->cif_fmt_in->field != V4L2_FIELD_INTERLACED) + ret = -EINVAL; + + if (stream->frame_phase == CIF_CSI_FRAME0_READY) { + if (!stream->curr_buf_rockit) + ret = -EINVAL; + stream->curr_buf_rockit = list_first_entry(&stream->rockit_buf_head, + struct rkcif_buffer, queue); + if (stream->curr_buf_rockit) { + list_del(&stream->curr_buf_rockit->queue); + buffer = stream->curr_buf_rockit; + } + } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { + if (!stream->next_buf_rockit) + ret = -EINVAL; + if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { + if (stream->next_buf_rockit != stream->curr_buf_rockit) { + stream->next_buf_rockit = stream->curr_buf_rockit; + buffer = stream->next_buf_rockit; + } else { + buffer = NULL; + } + + } else { + stream->next_buf_rockit = list_first_entry(&stream->rockit_buf_head, + struct rkcif_buffer, queue); + if (stream->next_buf_rockit) { + list_del(&stream->next_buf_rockit->queue); + buffer = stream->next_buf_rockit; + } + } + } + } else { + buffer = NULL; + if (dummy_buf->vaddr) { + if (stream->frame_phase == CIF_CSI_FRAME0_READY) { + stream->curr_buf_rockit = NULL; + } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { + if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { + stream->next_buf_rockit = stream->curr_buf_rockit; + buffer = stream->next_buf_rockit; + } else { + stream->next_buf_rockit = NULL; + } + } + } else if (stream->curr_buf_rockit && stream->next_buf_rockit && + stream->curr_buf_rockit != stream->next_buf_rockit) { + if (stream->frame_phase == CIF_CSI_FRAME0_READY) { + stream->curr_buf_rockit = stream->next_buf_rockit; + buffer = stream->next_buf_rockit; + } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { + stream->next_buf_rockit = stream->curr_buf_rockit; + buffer = stream->curr_buf_rockit; + } + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + } else { + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + } + } + stream->frame_phase_cache = stream->frame_phase; + + if (buffer) { + if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED && + stream->frame_phase == CIF_CSI_FRAME1_READY) { + rkcif_write_register(dev, frm_addr_y, + buffer->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2)); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, + buffer->buff_addr[RKCIF_PLANE_CBCR] + (channel->virtual_width / 2)); + } else { + rkcif_write_register(dev, frm_addr_y, + buffer->buff_addr[RKCIF_PLANE_Y]); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, + buffer->buff_addr[RKCIF_PLANE_CBCR]); + } + } else { + if (dummy_buf->vaddr) { + rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr); + dev->err_state |= (RKCIF_ERR_ID0_NOT_BUF << stream->id); + dev->irq_stats.not_active_buf_cnt[stream->id]++; + } else { + ret = -EINVAL; + dev->err_state |= (RKCIF_ERR_ID0_NOT_BUF << stream->id); + dev->irq_stats.not_active_buf_cnt[stream->id]++; + } + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); + return ret; +} + +static int rkcif_assign_new_buffer_pingpong_rockit(struct rkcif_stream *stream, + int init, int channel_id) +{ + int ret = 0; + + if (init) + rkcif_assign_new_buffer_init_rockit(stream, channel_id); + else + ret = rkcif_assign_new_buffer_update_rockit(stream, channel_id); return ret; } @@ -1712,7 +3325,7 @@ struct rkmodule_lvds_frm_sync_code *odd_sync_code = NULL; struct rkmodule_lvds_frm_sync_code *even_sync_code = NULL; - if (dev->hdr.mode == NO_HDR) { + if (dev->hdr.hdr_mode == NO_HDR || dev->hdr.hdr_mode == HDR_COMPR) { frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_LINEAR]; odd_sync_code = &frm_sync_code->odd_sync_code; even_sync_code = odd_sync_code; @@ -1720,12 +3333,12 @@ if (channel->id == RKCIF_STREAM_MIPI_ID0) frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_LONG]; - if (dev->hdr.mode == HDR_X2) { + if (dev->hdr.hdr_mode == HDR_X2) { if (channel->id == RKCIF_STREAM_MIPI_ID1) frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_SHORT]; else frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_LONG]; - } else if (dev->hdr.mode == HDR_X3) { + } else if (dev->hdr.hdr_mode == HDR_X3) { if (channel->id == RKCIF_STREAM_MIPI_ID1) frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_MEDIUM]; else if (channel->id == RKCIF_STREAM_MIPI_ID2) @@ -1761,12 +3374,44 @@ } } +static unsigned char get_csi_fmt_val(const struct cif_input_fmt *cif_fmt_in, + struct csi_channel_info *csi_info) +{ + unsigned char csi_fmt_val = 0; + + if (cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8 || + cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8) { + switch (csi_info->data_bit) { + case 8: + csi_fmt_val = CSI_WRDDR_TYPE_RAW8; + break; + case 10: + csi_fmt_val = CSI_WRDDR_TYPE_RAW10; + break; + case 12: + csi_fmt_val = CSI_WRDDR_TYPE_RAW12; + break; + default: + csi_fmt_val = CSI_WRDDR_TYPE_RAW12; + break; + } + } else if (cif_fmt_in->csi_fmt_val == CSI_WRDDR_TYPE_RGB888 || + cif_fmt_in->csi_fmt_val == CSI_WRDDR_TYPE_RGB565) { + csi_fmt_val = CSI_WRDDR_TYPE_RAW8; + } else { + csi_fmt_val = cif_fmt_in->csi_fmt_val; + } + return csi_fmt_val; +} + static int rkcif_csi_channel_init(struct rkcif_stream *stream, struct csi_channel_info *channel) { struct rkcif_device *dev = stream->cifdev; + struct sditf_priv *priv = dev->sditf[0]; const struct cif_output_fmt *fmt; u32 fourcc; + int vc = dev->channels[stream->id].vc; channel->enable = 1; channel->width = stream->pixm.width; @@ -1782,10 +3427,14 @@ if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888) channel->crop_st_x = 3 * stream->crop[CROP_SRC_ACT].left; + else if (channel->fmt_val == CSI_WRDDR_TYPE_RGB565) + channel->crop_st_x = 2 * stream->crop[CROP_SRC_ACT].left; else channel->crop_st_x = stream->crop[CROP_SRC_ACT].left; channel->crop_st_y = stream->crop[CROP_SRC_ACT].top; + if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF) + channel->crop_st_y *= dev->sditf_cnt; channel->width = stream->crop[CROP_SRC_ACT].width; channel->height = stream->crop[CROP_SRC_ACT].height; } else { @@ -1794,13 +3443,18 @@ channel->crop_en = 0; } - fmt = find_output_fmt(stream, stream->pixm.pixelformat); + if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF) + channel->height *= dev->sditf_cnt; + + fmt = rkcif_find_output_fmt(stream, stream->pixm.pixelformat); if (!fmt) { v4l2_err(&dev->v4l2_dev, "can not find output format: 0x%x", stream->pixm.pixelformat); return -EINVAL; } + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) + channel->width /= channel->capture_info.multi_dev.dev_num; /* * for mipi or lvds, when enable compact, the virtual width of raw10/raw12 * needs aligned with :ALIGN(bits_per_pixel * width / 8, 8), if enable 16bit mode @@ -1808,13 +3462,24 @@ * writing of ddr, aliged with 256 */ if (fmt->fmt_type == CIF_FMT_TYPE_RAW && stream->is_compact && - fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888) { - channel->virtual_width = ALIGN(channel->width * fmt->raw_bpp / 8, 256); + fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888 && + fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB565) { + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + channel->virtual_width = ALIGN(channel->width * 2 * fmt->raw_bpp / 8, 256); + channel->left_virtual_width = channel->width * fmt->raw_bpp / 8; + } else { + channel->virtual_width = ALIGN(channel->width * fmt->raw_bpp / 8, 256); + } } else { - channel->virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8); + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + channel->virtual_width = ALIGN(channel->width * 2 * fmt->bpp[0] / 8, 8); + channel->left_virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8); + } else { + channel->virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8); + } } - if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888) + if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888 || channel->fmt_val == CSI_WRDDR_TYPE_RGB565) channel->width = channel->width * fmt->bpp[0] / 8; /* * rk cif don't support output yuyv fmt data @@ -1822,36 +3487,53 @@ * and the width is double Because the real input fmt is * yuyv */ - fourcc = stream->cif_fmt_out->fourcc; + fourcc = stream->cif_fmt_out->fourcc; if (fourcc == V4L2_PIX_FMT_YUYV || fourcc == V4L2_PIX_FMT_YVYU || fourcc == V4L2_PIX_FMT_UYVY || fourcc == V4L2_PIX_FMT_VYUY) { - channel->fmt_val = CSI_WRDDR_TYPE_RAW8; - channel->width *= 2; + if (dev->chip_id < CHIP_RK3588_CIF) { + channel->fmt_val = CSI_WRDDR_TYPE_RAW8; + channel->width *= 2; + } channel->virtual_width *= 2; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) + channel->left_virtual_width *= 2; } if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { channel->virtual_width *= 2; channel->height /= 2; } + if (stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8 || + stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8) { + if (dev->channels[stream->id].data_type) + channel->data_type = dev->channels[stream->id].data_type; + else + channel->data_type = get_data_type(stream->cif_fmt_in->mbus_code, + channel->cmd_mode_en, + channel->dsi_input); + } else { + channel->data_type = get_data_type(stream->cif_fmt_in->mbus_code, + channel->cmd_mode_en, + channel->dsi_input); + } + channel->csi_fmt_val = get_csi_fmt_val(stream->cif_fmt_in, + &dev->channels[stream->id]); - channel->data_type = get_data_type(stream->cif_fmt_in->mbus_code, - channel->cmd_mode_en, channel->dsi_input); - - if ((dev->hdr.mode == NO_HDR && stream->vc >= 0) || - (dev->hdr.mode == HDR_X2 && stream->vc > 1) || - (dev->hdr.mode == HDR_X3 && stream->vc > 2)) - channel->vc = stream->vc; + if (dev->hdr.hdr_mode == NO_HDR || + dev->hdr.hdr_mode == HDR_COMPR || + (dev->hdr.hdr_mode == HDR_X2 && stream->id > 1) || + (dev->hdr.hdr_mode == HDR_X3 && stream->id > 2)) + channel->vc = vc < 4 ? vc : channel->id; else channel->vc = channel->id; - v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, + v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "%s: channel width %d, height %d, virtual_width %d, vc %d\n", __func__, channel->width, channel->height, channel->virtual_width, channel->vc); return 0; } static int rkcif_csi_channel_set(struct rkcif_stream *stream, - struct csi_channel_info *channel, - enum v4l2_mbus_type mbus_type) + struct csi_channel_info *channel, + enum v4l2_mbus_type mbus_type) { unsigned int val = 0x0; struct rkcif_device *dev = stream->cifdev; @@ -1872,10 +3554,9 @@ CSI_DMA_END_INTSTAT(channel->id) | CSI_LINE_INTSTAT(channel->id))); - /* enable id0 frame start int for sof(long frame, for hdr) */ - if (channel->id == RKCIF_STREAM_MIPI_ID0) - rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, - CSI_START_INTEN(channel->id)); + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, + CSI_START_INTEN(channel->id)); + if (detect_stream->is_line_wake_up) { rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, CSI_LINE_INTEN(channel->id)); @@ -1894,15 +3575,15 @@ CIF_MIPI_LVDS_SW_HURRY_VALUE_RK1808(0x3) | CIF_MIPI_LVDS_SW_HURRY_ENABLE_RK1808); - val = CIF_MIPI_LVDS_SW_PRESS_VALUE(0x7) | + val = CIF_MIPI_LVDS_SW_PRESS_VALUE(0x3) | CIF_MIPI_LVDS_SW_PRESS_ENABLE | - CIF_MIPI_LVDS_SW_HURRY_VALUE(0x7) | + CIF_MIPI_LVDS_SW_HURRY_VALUE(0x3) | CIF_MIPI_LVDS_SW_HURRY_ENABLE | CIF_MIPI_LVDS_SW_WATER_LINE_25 | CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE; - if (mbus_type == V4L2_MBUS_CSI2) { + if (mbus_type == V4L2_MBUS_CSI2_DPHY) { val &= ~CIF_MIPI_LVDS_SW_SEL_LVDS; - } else if (mbus_type == V4L2_MBUS_CCP2) { + } else if (mbus_type == V4L2_MBUS_CCP2) { if (channel->fmt_val == CSI_WRDDR_TYPE_RAW12) val |= CIF_MIPI_LVDS_SW_LVDS_WIDTH_12BITS; else if (channel->fmt_val == CSI_WRDDR_TYPE_RAW10) @@ -1937,7 +3618,7 @@ RKCIF_YUV_ADDR_STATE_INIT, channel->id); - if (mbus_type == V4L2_MBUS_CSI2) { + if (mbus_type == V4L2_MBUS_CSI2_DPHY) { //need always enable crop val = CSI_ENABLE_CAPTURE | channel->fmt_val | channel->cmd_mode_en << 4 | CSI_ENABLE_CROP | @@ -1949,7 +3630,7 @@ if (stream->cifdev->chip_id >= CHIP_RK3568_CIF) val |= stream->cif_fmt_in->csi_yuv_order; - } else if (mbus_type == V4L2_MBUS_CCP2) { + } else if (mbus_type == V4L2_MBUS_CCP2) { rkcif_csi_set_lvds_sav_eav(stream, channel); val = LVDS_ENABLE_CAPTURE | LVDS_MODE(channel->lvds_cfg.mode) | LVDS_MAIN_LANE(0) | LVDS_FID(0) | @@ -1961,15 +3642,403 @@ val &= ~LVDS_COMPACT; } if (stream->is_high_align) - val |= CSI_ENABLE_MIPI_HIGH_ALIGN; + val |= CSI_HIGH_ALIGN; else - val &= ~CSI_ENABLE_MIPI_HIGH_ALIGN; + val &= ~CSI_HIGH_ALIGN; rkcif_write_register(dev, get_reg_index_of_id_ctrl0(channel->id), val); return 0; } -static int rkcif_csi_stream_start(struct rkcif_stream *stream) +static int rkcif_dvp_get_input_yuv_order(struct rkcif_stream *stream) +{ + unsigned int mask; + const struct cif_input_fmt *fmt = stream->cif_fmt_in; + + switch (fmt->mbus_code) { + case MEDIA_BUS_FMT_UYVY8_2X8: + mask = CSI_YUV_INPUT_ORDER_UYVY >> 11; + break; + case MEDIA_BUS_FMT_VYUY8_2X8: + mask = CSI_YUV_INPUT_ORDER_VYUY >> 11; + break; + case MEDIA_BUS_FMT_YUYV8_2X8: + mask = CSI_YUV_INPUT_ORDER_YUYV >> 11; + break; + case MEDIA_BUS_FMT_YVYU8_2X8: + mask = CSI_YUV_INPUT_ORDER_YVYU >> 11; + break; + default: + mask = CSI_YUV_INPUT_ORDER_UYVY >> 11; + break; + } + return mask; +} + +static int rkcif_csi_get_output_type_mask(struct rkcif_stream *stream) +{ + unsigned int mask; + const struct cif_output_fmt *fmt = stream->cif_fmt_out; + + switch (fmt->fourcc) { + case V4L2_PIX_FMT_NV16: + mask = CSI_WRDDR_TYPE_YUV422SP_RK3588 | CSI_YUV_OUTPUT_ORDER_UYVY; + break; + case V4L2_PIX_FMT_NV61: + mask = CSI_WRDDR_TYPE_YUV422SP_RK3588 | CSI_YUV_OUTPUT_ORDER_VYUY; + break; + case V4L2_PIX_FMT_NV12: + mask = CSI_WRDDR_TYPE_YUV420SP_RK3588 | CSI_YUV_OUTPUT_ORDER_UYVY; + break; + case V4L2_PIX_FMT_NV21: + mask = CSI_WRDDR_TYPE_YUV420SP_RK3588 | CSI_YUV_OUTPUT_ORDER_VYUY; + break; + case V4L2_PIX_FMT_YUYV: + mask = CSI_WRDDR_TYPE_YUV_PACKET | CSI_YUV_OUTPUT_ORDER_YUYV; + break; + case V4L2_PIX_FMT_YVYU: + mask = CSI_WRDDR_TYPE_YUV_PACKET | CSI_YUV_OUTPUT_ORDER_YVYU; + break; + case V4L2_PIX_FMT_UYVY: + mask = CSI_WRDDR_TYPE_YUV_PACKET | CSI_YUV_OUTPUT_ORDER_UYVY; + break; + case V4L2_PIX_FMT_VYUY: + mask = CSI_WRDDR_TYPE_YUV_PACKET | CSI_YUV_OUTPUT_ORDER_VYUY; + break; + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_BGR666: + mask = CSI_WRDDR_TYPE_RAW_COMPACT; + break; + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_GREY: + case V4L2_PIX_FMT_Y10: + case V4L2_PIX_FMT_Y12: + if (stream->is_compact) + mask = CSI_WRDDR_TYPE_RAW_COMPACT; + else + mask = CSI_WRDDR_TYPE_RAW_UNCOMPACT; + break; + case V4L2_PIX_FMT_SBGGR16: + case V4L2_PIX_FMT_SGBRG16: + case V4L2_PIX_FMT_SGRBG16: + case V4L2_PIX_FMT_SRGGB16: + case V4L2_PIX_FMT_Y16: + mask = CSI_WRDDR_TYPE_RAW_UNCOMPACT; + break; + default: + mask = CSI_WRDDR_TYPE_RAW_COMPACT; + break; + } + return mask; +} + +static int rkcif_lvds_get_output_type_mask(struct rkcif_stream *stream) +{ + unsigned int mask; + const struct cif_output_fmt *fmt = stream->cif_fmt_out; + int wr_type_offset = 0; + int yuvout_offset = 0; + + if (stream->cifdev->chip_id == CHIP_RV1106_CIF) { + wr_type_offset = 17; + yuvout_offset = 9; + } + + switch (fmt->fourcc) { + case V4L2_PIX_FMT_NV16: + mask = (CSI_WRDDR_TYPE_YUV422SP_RK3588 << wr_type_offset) | + (CSI_YUV_OUTPUT_ORDER_UYVY << yuvout_offset); + break; + case V4L2_PIX_FMT_NV61: + mask = (CSI_WRDDR_TYPE_YUV422SP_RK3588 << wr_type_offset) | + (CSI_YUV_OUTPUT_ORDER_VYUY << yuvout_offset); + break; + case V4L2_PIX_FMT_NV12: + mask = (CSI_WRDDR_TYPE_YUV420SP_RK3588 << wr_type_offset) | + (CSI_YUV_OUTPUT_ORDER_UYVY << yuvout_offset); + break; + case V4L2_PIX_FMT_NV21: + mask = (CSI_WRDDR_TYPE_YUV420SP_RK3588 << wr_type_offset) | + (CSI_YUV_OUTPUT_ORDER_VYUY << yuvout_offset); + break; + case V4L2_PIX_FMT_YUYV: + mask = (CSI_WRDDR_TYPE_YUV_PACKET << wr_type_offset) | + (CSI_YUV_OUTPUT_ORDER_YUYV << yuvout_offset); + break; + case V4L2_PIX_FMT_YVYU: + mask = (CSI_WRDDR_TYPE_YUV_PACKET << wr_type_offset) | + (CSI_YUV_OUTPUT_ORDER_YVYU << yuvout_offset); + break; + case V4L2_PIX_FMT_UYVY: + mask = (CSI_WRDDR_TYPE_YUV_PACKET << wr_type_offset) | + (CSI_YUV_OUTPUT_ORDER_UYVY << yuvout_offset); + break; + case V4L2_PIX_FMT_VYUY: + mask = (CSI_WRDDR_TYPE_YUV_PACKET << wr_type_offset) | + (CSI_YUV_OUTPUT_ORDER_VYUY << yuvout_offset); + break; + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_BGR666: + mask = CSI_WRDDR_TYPE_RAW_COMPACT << wr_type_offset; + break; + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_GREY: + case V4L2_PIX_FMT_Y10: + case V4L2_PIX_FMT_Y12: + if (stream->is_compact) + mask = CSI_WRDDR_TYPE_RAW_COMPACT << wr_type_offset; + else + mask = CSI_WRDDR_TYPE_RAW_UNCOMPACT << wr_type_offset; + break; + case V4L2_PIX_FMT_SBGGR16: + case V4L2_PIX_FMT_SGBRG16: + case V4L2_PIX_FMT_SGRBG16: + case V4L2_PIX_FMT_SRGGB16: + case V4L2_PIX_FMT_Y16: + mask = CSI_WRDDR_TYPE_RAW_UNCOMPACT << wr_type_offset; + break; + default: + mask = CSI_WRDDR_TYPE_RAW_COMPACT << wr_type_offset; + break; + } + return mask; +} + +static void rkcif_modify_frame_skip_config(struct rkcif_stream *stream) +{ + if (stream->skip_info.skip_to_en) { + rkcif_disable_skip_frame(stream); + rkcif_enable_skip_frame(stream, + stream->skip_info.cap_m, + stream->skip_info.skip_n); + stream->skip_info.skip_to_en = false; + } else if (stream->skip_info.skip_to_dis) { + rkcif_disable_skip_frame(stream); + } +} + +/*config reg for rk3588*/ +static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, + struct csi_channel_info *channel, + enum v4l2_mbus_type mbus_type, unsigned int mode, + int index) +{ + unsigned int val = 0x0; + struct rkcif_device *dev = stream->cifdev; + struct rkcif_stream *detect_stream = &dev->stream[0]; + struct sditf_priv *priv = dev->sditf[0]; + struct rkmodule_capture_info *capture_info = &channel->capture_info; + unsigned int wait_line = 0x3fff; + unsigned int dma_en = 0; + int offset = 0; + + if (channel->id >= 4) + return -EINVAL; + + if (!channel->enable) { + rkcif_write_register(dev, get_reg_index_of_id_ctrl0(channel->id), + CSI_DISABLE_CAPTURE); + return 0; + } + + rkcif_write_register_and(dev, CIF_REG_MIPI_LVDS_INTSTAT, + ~(CSI_START_INTSTAT(channel->id) | + CSI_DMA_END_INTSTAT(channel->id) | + CSI_LINE_INTSTAT_V1(channel->id))); + + if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + index < capture_info->multi_dev.dev_num - 1)) { + + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, + CSI_START_INTEN(channel->id)); + + if (priv && priv->mode.rdbk_mode && detect_stream->is_line_wake_up) { + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, + CSI_LINE_INTEN_RK3588(channel->id)); + wait_line = dev->wait_line; + } + rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1, + wait_line << 16 | wait_line); + rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3, + wait_line << 16 | wait_line); + + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, + CSI_DMA_END_INTEN(channel->id)); + + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, + CSI_ALL_ERROR_INTEN_V1); + } + if (stream->cifdev->id_use_cnt == 0) { + val = CIF_MIPI_LVDS_SW_PRESS_VALUE_RK3588(0x3) | + CIF_MIPI_LVDS_SW_PRESS_ENABLE | + CIF_MIPI_LVDS_SW_HURRY_VALUE_RK3588(0x3) | + CIF_MIPI_LVDS_SW_HURRY_ENABLE | + CIF_MIPI_LVDS_SW_WATER_LINE_25 | + CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE; + if (mbus_type == V4L2_MBUS_CSI2_DPHY || + mbus_type == V4L2_MBUS_CSI2_CPHY) + val &= ~CIF_MIPI_LVDS_SW_SEL_LVDS_RV1106; + else + val |= CIF_MIPI_LVDS_SW_SEL_LVDS_RV1106; + rkcif_write_register(dev, CIF_REG_MIPI_LVDS_CTRL, val); + } +#if IS_ENABLED(CONFIG_CPU_RV1106) + if (channel->id == 1) + rv1106_sdmmc_get_lock(); +#endif + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + priv && priv->mode.rdbk_mode == RKISP_VICAP_ONLINE && + (dev->hdr.hdr_mode == NO_HDR || + (dev->hdr.hdr_mode == HDR_X2 && stream->id == 1) || + (dev->hdr.hdr_mode == HDR_X3 && stream->id == 2))) + offset = channel->capture_info.multi_dev.pixel_offset; + + rkcif_write_register(dev, get_reg_index_of_id_ctrl1(channel->id), + (channel->width + offset) | (channel->height << 16)); + +#if IS_ENABLED(CONFIG_CPU_RV1106) + if (channel->id == 1) + rv1106_sdmmc_put_lock(); +#endif + + if (channel->crop_en) + rkcif_write_register(dev, get_reg_index_of_id_crop_start(channel->id), + channel->crop_st_y << 16 | channel->crop_st_x); + + if (mode == RKCIF_STREAM_MODE_CAPTURE) + rkcif_assign_new_buffer_pingpong(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + else if (mode == RKCIF_STREAM_MODE_TOISP || + mode == RKCIF_STREAM_MODE_TOISP_RDBK) + rkcif_assign_new_buffer_pingpong_toisp(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + else if (mode == RKCIF_STREAM_MODE_ROCKIT) + rkcif_assign_new_buffer_pingpong_rockit(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + index == (capture_info->multi_dev.dev_num - 1) && + priv && priv->mode.rdbk_mode != RKISP_VICAP_ONLINE) + rkcif_write_register(dev, get_reg_index_of_id_crop_start(channel->id), + channel->crop_st_y << 16 | + (channel->crop_st_x + capture_info->multi_dev.pixel_offset)); + + rkcif_write_register(dev, get_reg_index_of_frm0_y_vlw(channel->id), + channel->virtual_width); + + if (stream->lack_buf_cnt == 2) + stream->dma_en = 0; + + if (stream->dma_en) { + if (mbus_type == V4L2_MBUS_CSI2_DPHY || + mbus_type == V4L2_MBUS_CSI2_CPHY) + dma_en = CSI_DMA_ENABLE; + else + dma_en = LVDS_DMAEN_RV1106; + } + if (mbus_type == V4L2_MBUS_CSI2_DPHY || + mbus_type == V4L2_MBUS_CSI2_CPHY) { + + if (stream->cifdev->hdr.esp.mode == HDR_LINE_CNT || + stream->cifdev->hdr.esp.mode == HDR_ID_CODE) + channel->vc = 0; + + val = CSI_ENABLE_CAPTURE | dma_en | + channel->cmd_mode_en << 26 | CSI_ENABLE_CROP_V1 | + channel->vc << 8 | channel->data_type << 10 | + channel->csi_fmt_val; + + val |= stream->cif_fmt_in->csi_yuv_order; + val |= rkcif_csi_get_output_type_mask(stream); + if (stream->cifdev->hdr.hdr_mode == NO_HDR || + stream->cifdev->hdr.hdr_mode == HDR_COMPR) + val |= CSI_NO_HDR; + else if (stream->cifdev->hdr.hdr_mode == HDR_X2) + val |= CSI_HDR2; + else if (stream->cifdev->hdr.hdr_mode == HDR_X3) + val |= CSI_HDR3; + if (stream->cifdev->hdr.esp.mode == HDR_NORMAL_VC) + val |= CSI_HDR_MODE_VC; + else if (stream->cifdev->hdr.esp.mode == HDR_LINE_CNT) + val |= CSI_HDR_MODE_LINE_CNT; + else if (stream->cifdev->hdr.esp.mode == HDR_ID_CODE) + val |= CSI_HDR_MODE_LINE_INFO; + if (stream->cifdev->hdr.hdr_mode != NO_HDR && + stream->cifdev->hdr.esp.mode == HDR_NORMAL_VC) + val |= CSI_HDR_VC_MODE_PROTECT; + if (stream->is_high_align) + val |= CSI_HIGH_ALIGN_RK3588; + else + val &= ~CSI_HIGH_ALIGN_RK3588; + rkcif_write_register(dev, get_reg_index_of_id_ctrl0(channel->id), val); + rkcif_write_register(dev, CIF_REG_MIPI_EFFECT_CODE_ID0, 0x02410251); + rkcif_write_register(dev, CIF_REG_MIPI_EFFECT_CODE_ID1, 0x02420252); + } else if (mbus_type == V4L2_MBUS_CCP2) { + rkcif_csi_set_lvds_sav_eav(stream, channel); + val = LVDS_ENABLE_CAPTURE_RV1106 | LVDS_MODE_RV1106(channel->lvds_cfg.mode) | + LVDS_MAIN_LANE_RV1106(0) | LVDS_FID_RV1106(0) | + LVDS_LANES_ENABLED_RV1106(dev->active_sensor->lanes) | + (channel->csi_fmt_val << 18) | + rkcif_lvds_get_output_type_mask(stream) | + (stream->cif_fmt_in->csi_yuv_order << 9) | + dma_en; + if (stream->cifdev->hdr.hdr_mode == HDR_X3) + val |= BIT(12); + rkcif_write_register(dev, get_reg_index_of_lvds_id_ctrl0(channel->id), val); + } + if (dev->chip_id >= CHIP_RV1106_CIF) + rkcif_modify_frame_skip_config(stream); + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + if (index == (capture_info->multi_dev.dev_num - 1)) + stream->cifdev->id_use_cnt++; + } else { + stream->cifdev->id_use_cnt++; + } + if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + index < capture_info->multi_dev.dev_num - 1)) { + if (mode == RKCIF_STREAM_MODE_CAPTURE) + rkcif_assign_new_buffer_pingpong(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + else if (mode == RKCIF_STREAM_MODE_TOISP || + mode == RKCIF_STREAM_MODE_TOISP_RDBK) + rkcif_assign_new_buffer_pingpong_toisp(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + } + return 0; +} + +static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode) { struct rkcif_device *dev = stream->cifdev; struct rkcif_sensor_info *active_sensor = dev->active_sensor; @@ -1977,23 +4046,22 @@ enum v4l2_mbus_type mbus_type = active_sensor->mbus.type; struct csi_channel_info *channel; u32 ret = 0; + int i; - if (stream->state != RKCIF_STATE_RESET_IN_STREAMING) + if (stream->state < RKCIF_STATE_STREAMING) { stream->frame_idx = 0; + stream->buf_wake_up_cnt = 0; + stream->frame_phase = 0; + stream->lack_buf_cnt = 0; + stream->is_in_vblank = false; + stream->is_change_toisp = false; + } - if (mbus_type == V4L2_MBUS_CSI2) { - rkcif_csi_get_vc_num(dev, flags); + rkcif_csi_get_vc_num(dev, flags); - channel = &dev->channels[stream->id]; - channel->id = stream->id; - rkcif_csi_channel_init(stream, channel); - rkcif_csi_channel_set(stream, channel, V4L2_MBUS_CSI2); - } else if (mbus_type == V4L2_MBUS_CCP2) { - rkcif_csi_get_vc_num(dev, flags); - - channel = &dev->channels[stream->id]; - channel->id = stream->id; - + channel = &dev->channels[stream->id]; + channel->id = stream->id; + if (mbus_type == V4L2_MBUS_CCP2) { ret = v4l2_subdev_call(dev->terminal_sensor.sd, core, ioctl, RKMODULE_GET_LVDS_CFG, &channel->lvds_cfg); @@ -2001,18 +4069,63 @@ v4l2_err(&dev->v4l2_dev, "Err: get lvds config failed!!\n"); return ret; } - - rkcif_csi_channel_init(stream, channel); - rkcif_csi_channel_set(stream, channel, V4L2_MBUS_CCP2); } - - stream->line_int_cnt = 0; - if (stream->is_line_wake_up) - stream->is_can_stop = false; - else - stream->is_can_stop = true; - stream->state = RKCIF_STATE_STREAMING; - dev->workmode = RKCIF_WORKMODE_PINGPONG; + rkcif_csi_channel_init(stream, channel); + if (stream->state != RKCIF_STATE_STREAMING) { + if (mode == RKCIF_STREAM_MODE_CAPTURE) { + stream->dma_en |= RKCIF_DMAEN_BY_VICAP; + } else if (mode == RKCIF_STREAM_MODE_TOISP_RDBK) { + stream->dma_en |= RKCIF_DMAEN_BY_ISP; + } else if (mode == RKCIF_STREAM_MODE_TOISP) { + if (dev->hdr.hdr_mode == HDR_X2 && + stream->id == 0) + stream->dma_en |= RKCIF_DMAEN_BY_ISP; + else if (dev->hdr.hdr_mode == HDR_X3 && (stream->id == 0 || stream->id == 1)) + stream->dma_en |= RKCIF_DMAEN_BY_ISP; + } else if (mode == RKCIF_STREAM_MODE_ROCKIT) { + stream->dma_en |= RKCIF_DMAEN_BY_ROCKIT; + } + if (stream->cifdev->chip_id < CHIP_RK3588_CIF) { + rkcif_csi_channel_set(stream, channel, mbus_type); + } else { + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + for (i = 0; i < channel->capture_info.multi_dev.dev_num; i++) { + dev->csi_host_idx = channel->capture_info.multi_dev.dev_idx[i]; + rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, i); + } + } else { + rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, 0); + } + } + } else { + if (stream->cifdev->chip_id >= CHIP_RK3588_CIF) { + if (mode == RKCIF_STREAM_MODE_CAPTURE) { + stream->to_en_dma = RKCIF_DMAEN_BY_VICAP; + } else if (mode == RKCIF_STREAM_MODE_TOISP_RDBK) { + stream->to_en_dma = RKCIF_DMAEN_BY_ISP; + } else if (mode == RKCIF_STREAM_MODE_TOISP) { + if (dev->hdr.hdr_mode == HDR_X2 && + stream->id == 0 && + (!stream->dma_en)) + stream->to_en_dma = RKCIF_DMAEN_BY_ISP; + else if (dev->hdr.hdr_mode == HDR_X3 && + (stream->id == 0 || stream->id == 1) && + (!stream->dma_en)) + stream->to_en_dma = RKCIF_DMAEN_BY_ISP; + } else if (mode == RKCIF_STREAM_MODE_ROCKIT) { + stream->to_en_dma = RKCIF_DMAEN_BY_ROCKIT; + } + } + } + if (stream->state != RKCIF_STATE_STREAMING) { + stream->line_int_cnt = 0; + if (stream->is_line_wake_up) + stream->is_can_stop = false; + else + stream->is_can_stop = true; + stream->state = RKCIF_STATE_STREAMING; + dev->workmode = RKCIF_WORKMODE_PINGPONG; + } return 0; } @@ -2023,17 +4136,28 @@ struct v4l2_mbus_config *mbus_cfg = &cif_dev->active_sensor->mbus; u32 val; int id; + int i = 0; - if (mbus_cfg->type == V4L2_MBUS_CSI2 || + stream->cifdev->id_use_cnt--; + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || mbus_cfg->type == V4L2_MBUS_CCP2) { id = stream->id; val = rkcif_read_register(cif_dev, get_reg_index_of_id_ctrl0(id)); - if (mbus_cfg->type == V4L2_MBUS_CSI2) - val &= ~CSI_ENABLE_CAPTURE; + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY) + val &= ~(CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE); else val &= ~LVDS_ENABLE_CAPTURE; - rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(id), val); + if (cif_dev->channels[id].capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + for (i = 0; i < cif_dev->channels[id].capture_info.multi_dev.dev_num; i++) { + cif_dev->csi_host_idx = cif_dev->channels[id].capture_info.multi_dev.dev_idx[i]; + rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(id), val); + } + } else { + rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(id), val); + } rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT, CSI_START_INTSTAT(id) | @@ -2045,8 +4169,25 @@ CSI_DMA_END_INTEN(id) | CSI_LINE_INTEN(id))); - rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN, - ~CSI_ALL_ERROR_INTEN); + if (stream->cifdev->chip_id < CHIP_RK3588_CIF) { + rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN, + ~CSI_ALL_ERROR_INTEN); + } else { + if (stream->cifdev->id_use_cnt == 0) { + rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN, + ~CSI_ALL_ERROR_INTEN_V1); + if (cif_dev->channels[id].capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + for (i = 0; i < cif_dev->channels[id].capture_info.multi_dev.dev_num; i++) { + cif_dev->csi_host_idx = cif_dev->channels[id].capture_info.multi_dev.dev_idx[i]; + rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_CTRL, + ~CSI_ENABLE_CAPTURE); + } + } else { + rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_CTRL, + ~CSI_ENABLE_CAPTURE); + } + } + } } else { if (atomic_read(&cif_dev->pipe.stream_cnt) == 1) { @@ -2056,16 +4197,17 @@ rkcif_write_register(cif_dev, CIF_REG_DVP_INTEN, 0x0); rkcif_write_register(cif_dev, CIF_REG_DVP_INTSTAT, 0x3ff); rkcif_write_register(cif_dev, CIF_REG_DVP_FRAME_STATUS, 0x0); + if (IS_ENABLED(CONFIG_CPU_RV1106)) + rkcif_config_dvp_pin(cif_dev, false); } - stream->is_dvp_yuv_addr_init = false; } - stream->state = RKCIF_STATE_READY; + stream->dma_en = 0; } static bool rkcif_is_extending_line_for_height(struct rkcif_device *dev, - struct rkcif_stream *stream, - const struct cif_input_fmt *fmt) + struct rkcif_stream *stream, + const struct cif_input_fmt *fmt) { bool is_extended = false; struct rkmodule_hdr_cfg hdr_cfg; @@ -2079,17 +4221,17 @@ RKMODULE_GET_HDR_CFG, &hdr_cfg); if (!ret) - dev->hdr.mode = hdr_cfg.hdr_mode; + dev->hdr = hdr_cfg; else - dev->hdr.mode = NO_HDR; + dev->hdr.hdr_mode = NO_HDR; } if (fmt && fmt->fmt_type == CIF_FMT_TYPE_RAW) { - if ((dev->hdr.mode == HDR_X2 && + if ((dev->hdr.hdr_mode == HDR_X2 && stream->id == RKCIF_STREAM_MIPI_ID1) || - (dev->hdr.mode == HDR_X3 && + (dev->hdr.hdr_mode == HDR_X3 && stream->id == RKCIF_STREAM_MIPI_ID2) || - (dev->hdr.mode == NO_HDR)) { + (dev->hdr.hdr_mode == NO_HDR)) { is_extended = true; } } @@ -2137,7 +4279,7 @@ plane_fmt = &pixm->plane_fmt[i]; sizes[i] = plane_fmt->sizeimage / height * h; } - + stream->total_buf_num = *num_buffers; v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "%s count %d, size %d, extended(%d, %d)\n", v4l2_type_names[queue->type], *num_buffers, sizes[0], is_extended, extend_line->is_extended); @@ -2146,91 +4288,192 @@ } static void rkcif_check_buffer_update_pingpong(struct rkcif_stream *stream, - int channel_id) + int channel_id) { struct rkcif_device *dev = stream->cifdev; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; struct rkcif_buffer *buffer = NULL; - struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; - u32 frm_addr_y, frm_addr_uv; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; + u32 frm_addr_y = 0, frm_addr_uv = 0; + u32 frm0_addr_y = 0, frm0_addr_uv = 0; + u32 frm1_addr_y = 0, frm1_addr_uv = 0; + u32 buff_addr_y = 0, buff_addr_cbcr = 0; + struct rkmodule_capture_info *capture_info = &dev->channels[channel_id].capture_info; unsigned long flags; + int frame_phase = 0; + bool is_dual_update_buf = false; + spin_lock_irqsave(&stream->vbq_lock, flags); if (stream->state == RKCIF_STATE_STREAMING && - stream->curr_buf == stream->next_buf && - stream->cif_fmt_in->field != V4L2_FIELD_INTERLACED && - (!dummy_buf->vaddr)) { - if (!stream->is_line_wake_up) { - if (mbus_cfg->type == V4L2_MBUS_CSI2 || + ((stream->curr_buf == stream->next_buf && + stream->cif_fmt_in->field != V4L2_FIELD_INTERLACED && + (!dummy_buf->vaddr)) || + stream->curr_buf == NULL || + stream->next_buf == NULL)) { + frame_phase = stream->frame_phase_cache; + if (!stream->is_line_wake_up || + (stream->is_line_wake_up && stream->frame_idx < 2)) { + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || mbus_cfg->type == V4L2_MBUS_CCP2) { - frm_addr_y = stream->frame_phase_cache & CIF_CSI_FRAME0_READY ? - get_reg_index_of_frm0_y_addr(channel_id) : - get_reg_index_of_frm1_y_addr(channel_id); - frm_addr_uv = stream->frame_phase_cache & CIF_CSI_FRAME0_READY ? - get_reg_index_of_frm0_uv_addr(channel_id) : - get_reg_index_of_frm1_uv_addr(channel_id); + frm0_addr_y = get_reg_index_of_frm0_y_addr(channel_id); + frm1_addr_y = get_reg_index_of_frm1_y_addr(channel_id); + frm0_addr_uv = get_reg_index_of_frm0_uv_addr(channel_id); + frm1_addr_uv = get_reg_index_of_frm1_uv_addr(channel_id); } else { - frm_addr_y = stream->frame_phase_cache & CIF_CSI_FRAME0_READY ? - get_dvp_reg_index_of_frm0_y_addr(channel_id) : - get_dvp_reg_index_of_frm1_y_addr(channel_id); - frm_addr_uv = stream->frame_phase_cache & CIF_CSI_FRAME0_READY ? - get_dvp_reg_index_of_frm0_uv_addr(channel_id) : - get_dvp_reg_index_of_frm1_uv_addr(channel_id); + frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(channel_id); + frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(channel_id); + frm0_addr_uv = get_dvp_reg_index_of_frm0_uv_addr(channel_id); + frm1_addr_uv = get_dvp_reg_index_of_frm1_uv_addr(channel_id); } - v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev, - "stream[%d] update buf in %s, stream->frame_phase_cache %d\n", - stream->id, __func__, stream->frame_phase_cache); - spin_lock_irqsave(&stream->vbq_lock, flags); + if (frame_phase & CIF_CSI_FRAME0_READY) { + frm_addr_y = frm0_addr_y; + frm_addr_uv = frm0_addr_uv; + } else { + frm_addr_y = frm1_addr_y; + frm_addr_uv = frm1_addr_uv; + } + if (!stream->dma_en && stream->curr_buf == NULL && stream->next_buf == NULL) + is_dual_update_buf = true; if (!list_empty(&stream->buf_head)) { - if (stream->frame_phase_cache == CIF_CSI_FRAME0_READY) { + if (frame_phase == CIF_CSI_FRAME0_READY) { stream->curr_buf = list_first_entry(&stream->buf_head, struct rkcif_buffer, queue); if (stream->curr_buf) { list_del(&stream->curr_buf->queue); buffer = stream->curr_buf; } - } else if (stream->frame_phase_cache == CIF_CSI_FRAME1_READY) { - stream->next_buf = list_first_entry(&stream->buf_head, + if (buffer && is_dual_update_buf) + stream->next_buf = buffer; + } else if (frame_phase == CIF_CSI_FRAME1_READY) { + if (stream->next_buf == NULL && + stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { + stream->next_buf = stream->curr_buf; + } else { + stream->next_buf = list_first_entry(&stream->buf_head, struct rkcif_buffer, queue); - if (stream->next_buf) { - list_del(&stream->next_buf->queue); - buffer = stream->next_buf; + if (stream->next_buf) { + list_del(&stream->next_buf->queue); + buffer = stream->next_buf; + } + if (buffer && is_dual_update_buf) + stream->curr_buf = buffer; + } + } + } else { + v4l2_info(&dev->v4l2_dev, "%s %d\n", __func__, __LINE__); + } + if (buffer) { + if (is_dual_update_buf) { + buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR]; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm0_addr_y, + frm0_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + rkcif_write_buff_addr_multi_dev_combine(stream, + frm1_addr_y, + frm1_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm0_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, + frm0_addr_uv, + buff_addr_cbcr); + rkcif_write_register(dev, frm1_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, + frm1_addr_uv, + buff_addr_cbcr); + } + } else { + + buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR]; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, + frm_addr_uv, + buff_addr_cbcr); } } } - spin_unlock_irqrestore(&stream->vbq_lock, flags); - if (buffer) { - rkcif_write_register(dev, frm_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR]); - } } else { - spin_lock_irqsave(&stream->vbq_lock, flags); + v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev, + "%s %d, is_wake_up %d, frame_idx %d\n", + __func__, __LINE__, stream->is_line_wake_up, stream->frame_idx); if (stream->curr_buf == stream->next_buf) { if (stream->frame_phase_cache == CIF_CSI_FRAME0_READY) { stream->curr_buf = list_first_entry(&stream->buf_head, struct rkcif_buffer, queue); + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, + "%s %d, stream[%d] buf idx %d\n", + __func__, __LINE__, stream->id, stream->curr_buf->vb.vb2_buf.index); if (stream->curr_buf) list_del(&stream->curr_buf->queue); } else if (stream->frame_phase_cache == CIF_CSI_FRAME1_READY) { stream->next_buf = list_first_entry(&stream->buf_head, struct rkcif_buffer, queue); + v4l2_dbg(4, rkcif_debug, &dev->v4l2_dev, + "%s %d, stream[%d] buf idx %d\n", + __func__, __LINE__, stream->id, stream->next_buf->vb.vb2_buf.index); if (stream->next_buf) list_del(&stream->next_buf->queue); } stream->is_buf_active = true; } - spin_unlock_irqrestore(&stream->vbq_lock, flags); } + v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev, + "%s, stream[%d] update buffer, frame_phase %d, is_stop %s, lack_buf_cnt %d\n", + __func__, stream->id, frame_phase, + (stream->dma_en ? "false" : "true"), + stream->lack_buf_cnt); + if (!stream->dma_en) { + if (stream->to_stop_dma) { + stream->to_stop_dma = 0; + wake_up(&stream->wq_stopped); + } else { + stream->to_en_dma = RKCIF_DMAEN_BY_VICAP; + v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev, + "%s stream[%d] start dma capture, frame cnt %d\n", + __func__, stream->id, stream->frame_idx); + } + } else { + v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev, + "%s %d, dma_en 0x%x, frame cnt %d\n", + __func__, __LINE__, stream->dma_en, stream->frame_idx); + } + if (stream->lack_buf_cnt) + stream->lack_buf_cnt--; + + } else { + v4l2_info(&dev->v4l2_dev, "%s %d, state %d, curr_buf %p, next_buf %p\n", + __func__, __LINE__, stream->state, stream->curr_buf, stream->next_buf); } + spin_unlock_irqrestore(&stream->vbq_lock, flags); + if (stream->to_en_dma) + rkcif_enable_dma_capture(stream, true); } /* * The vb2_buffer are stored in rkcif_buffer, in order to unify * mplane buffer and none-mplane buffer. */ -static void rkcif_buf_queue(struct vb2_buffer *vb) +void rkcif_buf_queue(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct rkcif_buffer *cifbuf = to_rkcif_buffer(vbuf); @@ -2239,8 +4482,32 @@ struct v4l2_pix_format_mplane *pixm = &stream->pixm; const struct cif_output_fmt *fmt = stream->cif_fmt_out; struct rkcif_hw *hw_dev = stream->cifdev->hw_dev; + struct rkcif_tools_buffer *tools_buf; + struct rkcif_tools_vdev *tools_vdev = stream->tools_vdev; unsigned long flags; int i; + bool is_find_tools_buf = false; + + if (tools_vdev) { + spin_lock_irqsave(&stream->tools_vdev->vbq_lock, flags); + if (!list_empty(&tools_vdev->src_buf_head)) { + list_for_each_entry(tools_buf, &tools_vdev->src_buf_head, list) { + if (tools_buf->vb == vbuf) { + is_find_tools_buf = true; + break; + } + } + if (is_find_tools_buf) { + if (tools_buf->use_cnt) + tools_buf->use_cnt--; + if (tools_buf->use_cnt) { + spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags); + return; + } + } + } + spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags); + } memset(cifbuf->buff_addr, 0, sizeof(cifbuf->buff_addr)); /* If mplanes > 1, every c-plane has its own m-plane, @@ -2249,7 +4516,7 @@ for (i = 0; i < fmt->mplanes; i++) { void *addr = vb2_plane_vaddr(vb, i); - if (hw_dev->iommu_en) { + if (hw_dev->is_dma_sg_ops) { struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, i); cifbuf->buff_addr[i] = sg_dma_address(sgt->sgl); @@ -2258,7 +4525,7 @@ } if (rkcif_debug && addr && !hw_dev->iommu_en) { memset(addr, 0, pixm->plane_fmt[i].sizeimage); - v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev, + v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev, "Clear buffer, size: 0x%08x\n", pixm->plane_fmt[i].sizeimage); } @@ -2272,40 +4539,240 @@ spin_lock_irqsave(&stream->vbq_lock, flags); list_add_tail(&cifbuf->queue, &stream->buf_head); spin_unlock_irqrestore(&stream->vbq_lock, flags); - if (stream->cifdev->workmode == RKCIF_WORKMODE_PINGPONG) + if (stream->dma_en & RKCIF_DMAEN_BY_ISP && (!cifbuf->dbuf)) { + struct rkisp_rx_buf *dbufs = NULL; + + dbufs = kzalloc(sizeof(struct rkisp_rx_buf), GFP_KERNEL); + + memset(dbufs, 0, sizeof(struct rkisp_rx_buf)); + if (stream->cifdev->hdr.hdr_mode == HDR_X2 && stream->id == 0) + dbufs->type = BUF_MIDDLE; + else if (stream->cifdev->hdr.hdr_mode == HDR_X3 && stream->id == 0) + dbufs->type = BUF_LONG; + else if (stream->cifdev->hdr.hdr_mode == HDR_X3 && stream->id == 1) + dbufs->type = BUF_MIDDLE; + cifbuf->dbuf = hw_dev->mem_ops->get_dmabuf(vb->planes[0].mem_priv, O_RDWR); + if (cifbuf->dbuf) + dbufs->dbuf = cifbuf->dbuf; + list_add_tail(&dbufs->list, &stream->rx_buf_head_vicap); + } + if (stream->cifdev->workmode == RKCIF_WORKMODE_PINGPONG && + stream->lack_buf_cnt) rkcif_check_buffer_update_pingpong(stream, stream->id); + v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev, + "stream[%d] buf queue, index: %d, dma_addr 0x%x\n", + stream->id, vb->index, cifbuf->buff_addr[0]); + atomic_inc(&stream->buf_cnt); +} + +void rkcif_free_rx_buf(struct rkcif_stream *stream, int buf_num) +{ + struct rkcif_rx_buffer *buf; + struct rkcif_device *dev = stream->cifdev; + struct sditf_priv *priv = dev->sditf[0]; + int i = 0; + unsigned long flags; + + if (!priv) + return; + + spin_lock_irqsave(&stream->vbq_lock, flags); + stream->curr_buf_toisp = NULL; + stream->next_buf_toisp = NULL; + INIT_LIST_HEAD(&stream->rx_buf_head); + spin_unlock_irqrestore(&stream->vbq_lock, flags); + + if (dev->is_thunderboot) + spin_lock_irqsave(&dev->buffree_lock, flags); + for (i = 0; i < buf_num; i++) { + buf = &stream->rx_buf[i]; + if (buf->dummy.is_free) + continue; + if (!dev->is_thunderboot) + rkcif_free_buffer(dev, &buf->dummy); + else + list_add_tail(&buf->list_free, &priv->buf_free_list); + atomic_dec(&stream->buf_cnt); + stream->total_buf_num--; + } + + if (dev->is_thunderboot) { + spin_unlock_irqrestore(&dev->buffree_lock, flags); + schedule_work(&priv->buffree_work.work); + } + stream->dma_en &= ~RKCIF_DMAEN_BY_ISP; v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev, - "stream[%d] buf queue, index: %d\n", - stream->id, vb->index); + "free rx_buf, buf_num %d\n", buf_num); +} + +int rkcif_init_rx_buf(struct rkcif_stream *stream, int buf_num) +{ + struct rkcif_device *dev = stream->cifdev; + struct v4l2_pix_format_mplane *pixm = &stream->pixm; + struct rkcif_dummy_buffer *dummy; + struct rkcif_rx_buffer *buf; + struct sditf_priv *priv = dev->sditf[0]; + int frm_type = 0; + int i = 0; + int ret = 0; + + if (!priv) + return -EINVAL; + + if (buf_num > RKISP_VICAP_BUF_CNT_MAX) + return -EINVAL; + + if (dev->hdr.hdr_mode == NO_HDR) { + if (stream->id == 0) + frm_type = BUF_SHORT; + else + return -EINVAL; + } else if (dev->hdr.hdr_mode == HDR_X2) { + if (stream->id == 0) + frm_type = BUF_MIDDLE; + else if (stream->id == 1) + frm_type = BUF_SHORT; + else + return -EINVAL; + } else if (dev->hdr.hdr_mode == HDR_X3) { + if (stream->id == 0) + frm_type = BUF_LONG; + else if (stream->id == 1) + frm_type = BUF_MIDDLE; + else if (stream->id == 2) + frm_type = BUF_SHORT; + else + return -EINVAL; + } + while (true) { + buf = &stream->rx_buf[i]; + memset(buf, 0, sizeof(*buf)); + dummy = &buf->dummy; + dummy->size = pixm->plane_fmt[0].sizeimage; + dummy->is_need_vaddr = true; + dummy->is_need_dbuf = true; + if (dev->is_thunderboot) { + buf->buf_idx = i; + ret = rkcif_alloc_reserved_mem_buf(dev, buf); + if (ret) { + priv->buf_num = i; + v4l2_info(&dev->v4l2_dev, + "reserved mem support alloc buf num %d, require buf num %d\n", + i, buf_num); + break; + } + if (dev->rdbk_debug) + v4l2_info(&dev->v4l2_dev, + "stream[%d] buf addr 0x%llx\n", + stream->id, (u64)dummy->dma_addr); + } else { + ret = rkcif_alloc_buffer(dev, dummy); + if (ret) { + priv->buf_num = i; + v4l2_info(&dev->v4l2_dev, + "alloc buf num %d, require buf num %d\n", + i, buf_num); + break; + } + buf->dbufs.dbuf = dummy->dbuf; + } + buf->dbufs.is_init = false; + buf->dbufs.type = frm_type; + list_add_tail(&buf->list, &stream->rx_buf_head); + dummy->is_free = false; + if (stream->is_compact) + buf->dbufs.is_uncompact = false; + else + buf->dbufs.is_uncompact = true; + if (priv && priv->mode.rdbk_mode == RKISP_VICAP_ONLINE && i == 0) { + buf->dbufs.is_first = true; + rkcif_s_rx_buffer(dev, &buf->dbufs); + } + i++; + if (!dev->is_thunderboot && i >= buf_num) { + break; + } else if (i >= RKISP_VICAP_BUF_CNT_MAX) { + priv->buf_num = i; + v4l2_info(&dev->v4l2_dev, + "reserved mem alloc buf num %d\n", i); + break; + } + v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, + "init rx_buf,dma_addr 0x%llx size: 0x%x\n", + (u64)dummy->dma_addr, pixm->plane_fmt[0].sizeimage); + } + if (priv->buf_num) { + stream->total_buf_num = priv->buf_num; + atomic_set(&stream->buf_cnt, priv->buf_num); + return 0; + } else { + return -EINVAL; + } } static int rkcif_create_dummy_buf(struct rkcif_stream *stream) { - u32 fourcc; struct rkcif_device *dev = stream->cifdev; - struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; - struct rkcif_hw *hw_dev = dev->hw_dev; + struct rkcif_hw *hw = dev->hw_dev; + struct rkcif_dummy_buffer *dummy_buf = &hw->dummy_buf; + struct rkcif_device *tmp_dev = NULL; + struct v4l2_subdev_frame_interval_enum fie; + struct v4l2_subdev_format fmt; + u32 max_size = 0; + u32 size = 0; + int ret = 0; + int i, j; - /* get a maximum plane size */ - dummy_buf->size = max3(stream->pixm.plane_fmt[0].bytesperline * - stream->pixm.height, - stream->pixm.plane_fmt[1].sizeimage, - stream->pixm.plane_fmt[2].sizeimage); - /* - * rk cif don't support output yuyv fmt data - * if user request yuyv fmt, the input mode must be RAW8 - * and the width is double Because the real input fmt is - * yuyv - */ - fourcc = stream->cif_fmt_out->fourcc; - if (fourcc == V4L2_PIX_FMT_YUYV || fourcc == V4L2_PIX_FMT_YVYU || - fourcc == V4L2_PIX_FMT_UYVY || fourcc == V4L2_PIX_FMT_VYUY) - dummy_buf->size *= 2; + for (i = 0; i < hw->dev_num; i++) { + tmp_dev = hw->cif_dev[i]; + if (tmp_dev->terminal_sensor.sd) { + for (j = 0; j < 32; j++) { + memset(&fie, 0, sizeof(fie)); + fie.index = j; + fie.pad = 0; + fie.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(tmp_dev->terminal_sensor.sd, + pad, enum_frame_interval, + NULL, &fie); + if (!ret) { + if (fie.code == MEDIA_BUS_FMT_RGB888_1X24) + size = fie.width * fie.height * 3; + else + size = fie.width * fie.height * 2; + v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, + "%s enum fmt, width %d, height %d\n", + __func__, fie.width, fie.height); + } else { + break; + } + if (size > max_size) + max_size = size; + } + } else { + continue; + } + } - dummy_buf->vaddr = dma_alloc_coherent(hw_dev->dev, dummy_buf->size, - &dummy_buf->dma_addr, - GFP_KERNEL); - if (!dummy_buf->vaddr) { + if (max_size == 0 && dev->terminal_sensor.sd) { + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(dev->terminal_sensor.sd, + pad, get_fmt, NULL, &fmt); + if (!ret) { + if (fmt.format.code == MEDIA_BUS_FMT_RGB888_1X24) + size = fmt.format.width * fmt.format.height * 3; + else + size = fmt.format.width * fmt.format.height * 2; + if (size > max_size) + max_size = size; + } + } + + dummy_buf->size = max_size; + + dummy_buf->is_need_vaddr = true; + dummy_buf->is_need_dbuf = true; + ret = rkcif_alloc_buffer(dev, dummy_buf); + if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to allocate the memory for dummy buffer\n"); return -ENOMEM; @@ -2314,18 +4781,16 @@ v4l2_info(&dev->v4l2_dev, "Allocate dummy buffer, size: 0x%08x\n", dummy_buf->size); - return 0; + return ret; } static void rkcif_destroy_dummy_buf(struct rkcif_stream *stream) { struct rkcif_device *dev = stream->cifdev; - struct rkcif_dummy_buffer *dummy_buf = &dev->dummy_buf; - struct rkcif_hw *hw_dev = dev->hw_dev; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; if (dummy_buf->vaddr) - dma_free_coherent(hw_dev->dev, dummy_buf->size, - dummy_buf->vaddr, dummy_buf->dma_addr); + rkcif_free_buffer(dev, dummy_buf); dummy_buf->dma_addr = 0; dummy_buf->vaddr = NULL; } @@ -2339,7 +4804,7 @@ if (dev->luma_vdev.enable) rkcif_stop_luma(&dev->luma_vdev); - if (dev->hdr.mode != NO_HDR) { + if (dev->hdr.hdr_mode != NO_HDR) { if (dev->chip_id == CHIP_RK1808_CIF) { val = rkcif_read_register(dev, CIF_REG_MIPI_WATER_LINE); val |= CIF_MIPI_LVDS_SW_DMA_IDLE_RK1808; @@ -2363,14 +4828,22 @@ reset_control_deassert(cif_hw->cif_rst[i]); if (cif_hw->iommu_en) { - struct iommu_domain *domain; - - domain = iommu_get_domain_for_dev(cif_hw->dev); - if (domain) { - iommu_detach_device(domain, cif_hw->dev); - iommu_attach_device(domain, cif_hw->dev); - } + rockchip_iommu_disable(cif_hw->dev); + rockchip_iommu_enable(cif_hw->dev); } +} + +void rkcif_do_soft_reset(struct rkcif_device *dev) +{ + if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY || + dev->active_sensor->mbus.type == V4L2_MBUS_CCP2) + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_CTRL, 0x000A0000); + else + rkcif_write_register_or(dev, CIF_REG_DVP_CTRL, 0x000A0000); + usleep_range(10, 20); + v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, + "vicap do soft reset 0x%x\n", 0x000A0000); } static void rkcif_release_rdbk_buf(struct rkcif_stream *stream) @@ -2415,9 +4888,52 @@ } -static void rkcif_stop_streaming(struct vb2_queue *queue) +static void rkcif_detach_sync_mode(struct rkcif_device *cif_dev) { - struct rkcif_stream *stream = queue->drv_priv; + int i = 0; + struct rkcif_hw *hw = cif_dev->hw_dev; + struct rkcif_device *tmp_dev; + struct rkcif_multi_sync_config *sync_config; + + if ((!cif_dev->sync_cfg.type) || + (atomic_read(&cif_dev->pipe.stream_cnt) != 0)) + return; + mutex_lock(&hw->dev_lock); + memset(&cif_dev->sync_cfg, 0, sizeof(cif_dev->sync_cfg)); + sync_config = &hw->sync_config[cif_dev->sync_cfg.group]; + sync_config->streaming_cnt--; + if (cif_dev->sync_cfg.type == EXTERNAL_MASTER_MODE) { + for (i = 0; i < sync_config->ext_master.count; i++) { + tmp_dev = sync_config->ext_master.cif_dev[i]; + if (tmp_dev == cif_dev) { + sync_config->ext_master.is_streaming[i] = false; + break; + } + } + } + if (cif_dev->sync_cfg.type == INTERNAL_MASTER_MODE) + sync_config->int_master.is_streaming[0] = false; + if (cif_dev->sync_cfg.type == SLAVE_MODE) { + for (i = 0; i < sync_config->slave.count; i++) { + tmp_dev = sync_config->slave.cif_dev[i]; + if (tmp_dev == cif_dev) { + sync_config->slave.is_streaming[i] = false; + break; + } + } + } + + if (!sync_config->streaming_cnt && sync_config->is_attach) { + sync_config->is_attach = false; + sync_config->mode = RKCIF_NOSYNC_MODE; + sync_config->dev_cnt = 0; + } + mutex_unlock(&hw->dev_lock); +} + +void rkcif_do_stop_stream(struct rkcif_stream *stream, + unsigned int mode) +{ struct rkcif_vdev_node *node = &stream->vnode; struct rkcif_device *dev = stream->cifdev; struct v4l2_device *v4l2_dev = &dev->v4l2_dev; @@ -2427,93 +4943,170 @@ bool can_reset = true; int i; unsigned long flags; + u32 vblank = 0; + u32 frame_time_ns = 0; + u64 cur_time = 0; + u64 fs_time = 0; - mutex_lock(&dev->hw_dev->dev_lock); + mutex_lock(&dev->stream_lock); - v4l2_info(&dev->v4l2_dev, "stream[%d] start stopping\n", stream->id); + v4l2_info(&dev->v4l2_dev, "stream[%d] start stopping, total mode 0x%x, cur 0x%x\n", + stream->id, stream->cur_stream_mode, mode); - stream->stopping = true; + if (mode == stream->cur_stream_mode) { + if (stream->dma_en) { + if (!dev->sensor_linetime) + dev->sensor_linetime = rkcif_get_linetime(stream); + vblank = rkcif_get_sensor_vblank(dev); + if (vblank) { + frame_time_ns = (vblank + dev->terminal_sensor.raw_rect.height) * + dev->sensor_linetime; + spin_lock_irqsave(&stream->fps_lock, flags); + fs_time = stream->readout.fs_timestamp; + spin_unlock_irqrestore(&stream->fps_lock, flags); + cur_time = ktime_get_ns(); + if (cur_time > fs_time && + cur_time - fs_time < (frame_time_ns - 10000000)) { + spin_lock_irqsave(&stream->vbq_lock, flags); + if (stream->dma_en & RKCIF_DMAEN_BY_VICAP) + stream->to_stop_dma = RKCIF_DMAEN_BY_VICAP; + else if (stream->dma_en & RKCIF_DMAEN_BY_ISP) + stream->to_stop_dma = RKCIF_DMAEN_BY_ISP; + stream->is_stop_capture = true; + rkcif_stop_dma_capture(stream); + spin_unlock_irqrestore(&stream->vbq_lock, flags); + } + } + } + stream->stopping = true; + ret = wait_event_timeout(stream->wq_stopped, + stream->state != RKCIF_STATE_STREAMING, + msecs_to_jiffies(500)); + if (!ret) { + rkcif_stream_stop(stream); + stream->stopping = false; + } - ret = wait_event_timeout(stream->wq_stopped, - stream->state != RKCIF_STATE_STREAMING, - msecs_to_jiffies(1000)); - if (!ret) { - rkcif_stream_stop(stream); - stream->stopping = false; + media_pipeline_stop(&node->vdev.entity); + ret = dev->pipe.set_stream(&dev->pipe, false); + if (ret < 0) + v4l2_err(v4l2_dev, "pipeline stream-off failed error:%d\n", + ret); + + dev->is_start_hdr = false; + stream->is_dvp_yuv_addr_init = false; + if (stream->skip_info.skip_en) { + stream->skip_info.skip_en = false; + stream->skip_info.skip_to_en = true; + } + } else if (mode == RKCIF_STREAM_MODE_CAPTURE && stream->dma_en & RKCIF_DMAEN_BY_VICAP) { + //only stop dma + stream->to_stop_dma = RKCIF_DMAEN_BY_VICAP; + stream->is_wait_dma_stop = true; + wait_event_timeout(stream->wq_stopped, + !stream->is_wait_dma_stop, + msecs_to_jiffies(1000)); + } else if (mode == RKCIF_STREAM_MODE_TOISP && stream->dma_en & RKCIF_DMAEN_BY_VICAP) { + //only stop dma + stream->to_stop_dma = RKCIF_DMAEN_BY_ISP; + stream->is_wait_dma_stop = true; + wait_event_timeout(stream->wq_stopped, + !stream->is_wait_dma_stop, + msecs_to_jiffies(1000)); + } + if ((mode & RKCIF_STREAM_MODE_CAPTURE) == RKCIF_STREAM_MODE_CAPTURE) { + /* release buffers */ + spin_lock_irqsave(&stream->vbq_lock, flags); + if (stream->curr_buf) + list_add_tail(&stream->curr_buf->queue, &stream->buf_head); + if (stream->next_buf && + stream->next_buf != stream->curr_buf) + list_add_tail(&stream->next_buf->queue, &stream->buf_head); + spin_unlock_irqrestore(&stream->vbq_lock, flags); + + stream->curr_buf = NULL; + stream->next_buf = NULL; + + if (dev->hdr.hdr_mode == HDR_X2 || + dev->hdr.hdr_mode == HDR_X3) + rkcif_release_rdbk_buf(stream); + + rkcif_rx_buffer_free(stream); + list_for_each_entry(buf, &stream->buf_head, queue) { + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, + "stream[%d] buf return addr 0x%x\n", + stream->id, buf->buff_addr[0]); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + INIT_LIST_HEAD(&stream->buf_head); + while (!list_empty(&stream->vb_done_list)) { + buf = list_first_entry(&stream->vb_done_list, + struct rkcif_buffer, queue); + if (buf) { + list_del(&buf->queue); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + } + stream->total_buf_num = 0; + atomic_set(&stream->buf_cnt, 0); + stream->lack_buf_cnt = 0; + stream->dma_en &= ~RKCIF_DMAEN_BY_VICAP; } - media_pipeline_stop(&node->vdev.entity); - ret = dev->pipe.set_stream(&dev->pipe, false); - if (ret < 0) - v4l2_err(v4l2_dev, "pipeline stream-off failed error:%d\n", - ret); - - dev->is_start_hdr = false; - stream->is_dvp_yuv_addr_init = false; - - /* release buffers */ - if (stream->curr_buf) - list_add_tail(&stream->curr_buf->queue, &stream->buf_head); - - if (stream->next_buf && - stream->next_buf != stream->curr_buf) - list_add_tail(&stream->next_buf->queue, &stream->buf_head); - - if (dev->hdr.mode != NO_HDR) - rkcif_release_rdbk_buf(stream); - - stream->curr_buf = NULL; - stream->next_buf = NULL; - - while (!list_empty(&stream->buf_head)) { - buf = list_first_entry(&stream->buf_head, - struct rkcif_buffer, queue); - list_del(&buf->queue); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - } - - ret = dev->pipe.close(&dev->pipe); - if (ret < 0) - v4l2_err(v4l2_dev, "pipeline close failed error:%d\n", ret); - - if (dev->hdr.mode == HDR_X2) { - if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_READY && - dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_READY) { + if (mode == stream->cur_stream_mode) { + ret = dev->pipe.close(&dev->pipe); + if (ret < 0) + v4l2_err(v4l2_dev, "pipeline close failed error:%d\n", ret); + if (dev->hdr.hdr_mode == HDR_X2) { + if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_READY && + dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_READY) { + dev->can_be_reset = true; + } + } else if (dev->hdr.hdr_mode == HDR_X3) { + if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_READY && + dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_READY && + dev->stream[RKCIF_STREAM_MIPI_ID2].state == RKCIF_STATE_READY) { + dev->can_be_reset = true; + } + } else { dev->can_be_reset = true; } - } else if (dev->hdr.mode == HDR_X3) { - if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_READY && - dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_READY && - dev->stream[RKCIF_STREAM_MIPI_ID2].state == RKCIF_STATE_READY) { - dev->can_be_reset = true; + mutex_lock(&hw_dev->dev_lock); + for (i = 0; i < hw_dev->dev_num; i++) { + if (atomic_read(&hw_dev->cif_dev[i]->pipe.stream_cnt) != 0) { + can_reset = false; + break; + } } - } else { - dev->can_be_reset = true; - } - - spin_lock_irqsave(&hw_dev->hw_timer.timer_lock, flags); - for (i = 0; i < hw_dev->dev_num; i++) { - if (atomic_read(&hw_dev->cif_dev[i]->pipe.stream_cnt) != 0) { - can_reset = false; - break; + mutex_unlock(&hw_dev->dev_lock); + if (dev->can_be_reset && dev->chip_id >= CHIP_RK3588_CIF) + rkcif_do_soft_reset(dev); + if (dev->can_be_reset && can_reset) { + dev->can_be_reset = false; + dev->reset_work_cancel = true; + dev->early_line = 0; + dev->sensor_linetime = 0; + dev->wait_line = 0; + stream->is_line_wake_up = false; } + if (can_reset && hw_dev->dummy_buf.vaddr) + rkcif_destroy_dummy_buf(stream); } + if (mode == RKCIF_STREAM_MODE_CAPTURE) + tasklet_disable(&stream->vb_done_tasklet); - if (dev->can_be_reset && can_reset) { - rkcif_do_cru_reset(dev); - dev->can_be_reset = false; - hw_dev->reset_work_cancel = true; - hw_dev->hw_timer.is_running = false; - hw_dev->reset_info.is_need_reset = 0; - } - spin_unlock_irqrestore(&hw_dev->hw_timer.timer_lock, flags); + stream->cur_stream_mode &= ~mode; + INIT_LIST_HEAD(&stream->vb_done_list); + v4l2_info(&dev->v4l2_dev, "stream[%d] stopping finished, dma_en 0x%x\n", stream->id, stream->dma_en); + mutex_unlock(&dev->stream_lock); + rkcif_detach_sync_mode(dev); +} - if (!atomic_read(&dev->pipe.stream_cnt) && dev->dummy_buf.vaddr) - rkcif_destroy_dummy_buf(stream); +static void rkcif_stop_streaming(struct vb2_queue *queue) +{ + struct rkcif_stream *stream = queue->drv_priv; - v4l2_info(&dev->v4l2_dev, "stream[%d] stopping finished\n", stream->id); - - mutex_unlock(&dev->hw_dev->dev_lock); + rkcif_do_stop_stream(stream, RKCIF_STREAM_MODE_CAPTURE); } /* @@ -2589,6 +5182,70 @@ return mode; } +static u32 rkcif_determine_input_mode_rk3588(struct rkcif_stream *stream) +{ + struct rkcif_device *dev = stream->cifdev; + struct rkcif_sensor_info *sensor_info = dev->active_sensor; + struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor; + __u32 intf = BT656_STD_RAW; + u32 mode = INPUT_MODE_YUV; + v4l2_std_id std; + int ret; + + ret = v4l2_subdev_call(sensor_info->sd, video, querystd, &std); + if (ret == 0) { + /* retrieve std from sensor if exist */ + switch (std) { + case V4L2_STD_NTSC: + case V4L2_STD_PAL: + mode = INPUT_BT656_YUV422; + break; + case V4L2_STD_ATSC: + mode = INPUT_BT1120_YUV422; + break; + default: + v4l2_err(&dev->v4l2_dev, + "std: %lld is not supported", std); + } + mode |= CSI_WRDDR_TYPE_RAW8 << 6; + } else { + /* determine input mode by mbus_code (fmt_type) */ + switch (stream->cif_fmt_in->fmt_type) { + case CIF_FMT_TYPE_YUV: + if (sensor_info->mbus.type == V4L2_MBUS_BT656) { + if ((sensor_info->mbus.flags & CIF_DVP_PCLK_DUAL_EDGE) == CIF_DVP_PCLK_DUAL_EDGE) + mode = INPUT_BT1120_YUV422; + else + mode = INPUT_BT656_YUV422; + } else { + mode = INPUT_BT601_YUV422; + } + mode |= CSI_WRDDR_TYPE_RAW8 << 6; + break; + case CIF_FMT_TYPE_RAW: + ret = v4l2_subdev_call(terminal_sensor->sd, + core, ioctl, + RKMODULE_GET_BT656_INTF_TYPE, + &intf); + if (!ret) { + if (intf == BT656_SONY_RAW) + mode = INPUT_SONY_RAW; + else + mode = INPUT_BT601_RAW; + } else { + mode = INPUT_BT601_RAW; + } + mode |= stream->cif_fmt_in->csi_fmt_val << 6; + break; + } + } + if (stream->cif_fmt_in->field == V4L2_FIELD_NONE) + mode |= TRANSMIT_PROGRESS_RK3588; + else + mode |= TRANSMIT_INTERFACE_RK3588; + return mode; +} + static inline u32 rkcif_scl_ctl(struct rkcif_stream *stream) { u32 fmt_type = stream->cif_fmt_in->fmt_type; @@ -2613,15 +5270,21 @@ case V4L2_PIX_FMT_NV61: case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: case V4L2_PIX_FMT_GREY: case V4L2_PIX_FMT_Y16: bpp = fmt->bpp[plane_index]; break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + if (stream->cifdev->chip_id < CHIP_RK3588_CIF) + bpp = fmt->bpp[plane_index]; + else + bpp = fmt->bpp[plane_index + 1]; + break; case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_BGR666: case V4L2_PIX_FMT_SRGGB8: @@ -2637,8 +5300,13 @@ case V4L2_PIX_FMT_SGBRG12: case V4L2_PIX_FMT_SBGGR12: case V4L2_PIX_FMT_SBGGR16: + case V4L2_PIX_FMT_SGBRG16: + case V4L2_PIX_FMT_SGRBG16: + case V4L2_PIX_FMT_SRGGB16: case V4l2_PIX_FMT_SPD16: case V4l2_PIX_FMT_EBD8: + case V4L2_PIX_FMT_Y10: + case V4L2_PIX_FMT_Y12: if (stream->cifdev->chip_id < CHIP_RV1126_CIF) { bpp = max(fmt->bpp[plane_index], (u8)CIF_RAW_STORED_BIT_WIDTH); cal = CIF_RAW_STORED_BIT_WIDTH; @@ -2654,7 +5322,8 @@ } break; default: - pr_err("fourcc: %d is not supported!\n", fmt->fourcc); + v4l2_err(&stream->cifdev->v4l2_dev, "fourcc: %d is not supported!\n", + fmt->fourcc); break; } } @@ -2688,7 +5357,8 @@ if (dev->terminal_sensor.sd) { input_sel.target = V4L2_SEL_TGT_CROP_BOUNDS; - + input_sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; + input_sel.pad = 0; ret = v4l2_subdev_call(dev->terminal_sensor.sd, pad, get_selection, NULL, &input_sel); @@ -2698,6 +5368,7 @@ stream->crop_mask |= CROP_SRC_SENSOR_MASK; dev->terminal_sensor.selection = input_sel; } else { + stream->crop_mask &= ~CROP_SRC_SENSOR_MASK; dev->terminal_sensor.selection.r = dev->terminal_sensor.raw_rect; } } @@ -2718,8 +5389,10 @@ stream->crop[CROP_SRC_ACT].top = stream->crop[CROP_SRC_USR].top + stream->crop[CROP_SRC_SENSOR].top; } - } else { + } else if (stream->crop_mask & CROP_SRC_SENSOR_MASK) { stream->crop[CROP_SRC_ACT] = stream->crop[CROP_SRC_SENSOR]; + } else { + stream->crop[CROP_SRC_ACT] = dev->terminal_sensor.raw_rect; } } @@ -2733,11 +5406,11 @@ struct rkcif_device *dev = stream->cifdev; struct v4l2_device *v4l2_dev = &dev->v4l2_dev; struct v4l2_rect input, *crop; - int vc; if (dev->terminal_sensor.sd) { - stream->cif_fmt_in = get_input_fmt(dev->terminal_sensor.sd, - &input, stream->id, &vc); + stream->cif_fmt_in = rkcif_get_input_fmt(dev, + &input, stream->id, + &dev->channels[stream->id]); if (!stream->cif_fmt_in) { v4l2_err(v4l2_dev, "Input fmt is invalid\n"); return -EINVAL; @@ -2747,7 +5420,6 @@ return -EINVAL; } - stream->vc = vc; if (stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8 || stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8) { stream->crop_enable = false; @@ -2765,7 +5437,9 @@ return -EINVAL; } - if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) { + if (dev->active_sensor && + (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY)) { if (crop->left > 0) { int align_x = get_csi_crop_align(stream->cif_fmt_in); @@ -2776,7 +5450,7 @@ return -EINVAL; } } - } else if (dev->active_sensor->mbus.type == V4L2_MBUS_CCP2) { + } else if (dev->active_sensor && dev->active_sensor->mbus.type == V4L2_MBUS_CCP2) { if (crop->left % 4 != 0 && crop->width % 4 != 0) { v4l2_err(v4l2_dev, "ERROR: lvds crop left and width must align %d\n", 4); @@ -2808,8 +5482,8 @@ __func__, stream->id); return -ENODEV; } - ret = v4l2_subdev_call(sensor->sd, video, g_mbus_config, - &sensor->mbus); + ret = v4l2_subdev_call(sensor->sd, pad, get_mbus_config, + 0, &sensor->mbus); if (ret && ret != -ENOIOCTLCMD) { v4l2_err(&stream->cifdev->v4l2_dev, "%s: get remote %s mbus failed!\n", __func__, sensor->sd->name); @@ -2821,24 +5495,38 @@ terminal_sensor = &stream->cifdev->terminal_sensor; get_remote_terminal_sensor(stream, &terminal_sensor->sd); if (terminal_sensor->sd) { - ret = v4l2_subdev_call(terminal_sensor->sd, video, g_mbus_config, - &terminal_sensor->mbus); + ret = v4l2_subdev_call(terminal_sensor->sd, pad, get_mbus_config, + 0, &terminal_sensor->mbus); if (ret && ret != -ENOIOCTLCMD) { v4l2_err(&stream->cifdev->v4l2_dev, "%s: get terminal %s mbus failed!\n", __func__, terminal_sensor->sd->name); return ret; } - if (v4l2_subdev_call(terminal_sensor->sd, core, ioctl, RKMODULE_GET_CSI_DSI_INFO, - &terminal_sensor->dsi_input_en)) { - v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev, - "%s: get terminal %s CSI/DSI sel failed, default csi input!\n", + ret = v4l2_subdev_call(terminal_sensor->sd, video, + g_frame_interval, &terminal_sensor->fi); + if (ret) { + v4l2_err(&stream->cifdev->v4l2_dev, + "%s: get terminal %s g_frame_interval failed!\n", __func__, terminal_sensor->sd->name); + return ret; + } + if (v4l2_subdev_call(terminal_sensor->sd, core, ioctl, RKMODULE_GET_CSI_DSI_INFO, + &terminal_sensor->dsi_input_en)) { + v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev, + "%s: get terminal %s CSI/DSI sel failed, default csi input!\n", + __func__, terminal_sensor->sd->name); terminal_sensor->dsi_input_en = 0; } + } else { + v4l2_err(&stream->cifdev->v4l2_dev, + "%s: stream[%d] get remote terminal sensor failed!\n", + __func__, stream->id); + return -ENODEV; } - if (terminal_sensor->mbus.type == V4L2_MBUS_CSI2 || + if (terminal_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + terminal_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY || terminal_sensor->mbus.type == V4L2_MBUS_CCP2) { switch (terminal_sensor->mbus.flags & V4L2_MBUS_CSI2_LANES) { case V4L2_MBUS_CSI2_1_LANE: @@ -2865,7 +5553,85 @@ return ret; } -static int rkcif_stream_start(struct rkcif_stream *stream) +static int rkcif_dvp_get_output_type_mask(struct rkcif_stream *stream) +{ + unsigned int mask; + const struct cif_output_fmt *fmt = stream->cif_fmt_out; + + switch (fmt->fourcc) { + case V4L2_PIX_FMT_NV16: + mask = (CSI_WRDDR_TYPE_YUV422SP_RK3588 << 11) | + (CSI_YUV_OUTPUT_ORDER_UYVY << 1); + break; + case V4L2_PIX_FMT_NV61: + mask = (CSI_WRDDR_TYPE_YUV422SP_RK3588 << 11) | + (CSI_YUV_OUTPUT_ORDER_VYUY << 1); + break; + case V4L2_PIX_FMT_NV12: + mask = (CSI_WRDDR_TYPE_YUV420SP_RK3588 << 11) | + (CSI_YUV_OUTPUT_ORDER_UYVY << 1); + break; + case V4L2_PIX_FMT_NV21: + mask = (CSI_WRDDR_TYPE_YUV420SP_RK3588 << 11) | + (CSI_YUV_OUTPUT_ORDER_VYUY << 1); + break; + case V4L2_PIX_FMT_YUYV: + mask = (CSI_WRDDR_TYPE_YUV_PACKET << 11) | + (CSI_YUV_OUTPUT_ORDER_YUYV << 1); + break; + case V4L2_PIX_FMT_YVYU: + mask = (CSI_WRDDR_TYPE_YUV_PACKET << 11) | + (CSI_YUV_OUTPUT_ORDER_YVYU << 1); + break; + case V4L2_PIX_FMT_UYVY: + mask = (CSI_WRDDR_TYPE_YUV_PACKET << 11) | + (CSI_YUV_OUTPUT_ORDER_UYVY << 1); + break; + case V4L2_PIX_FMT_VYUY: + mask = (CSI_WRDDR_TYPE_YUV_PACKET << 11) | + (CSI_YUV_OUTPUT_ORDER_VYUY << 1); + break; + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_BGR666: + mask = CSI_WRDDR_TYPE_RAW_COMPACT << 11; + break; + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_GREY: + case V4L2_PIX_FMT_Y10: + case V4L2_PIX_FMT_Y12: + if (stream->is_compact) + mask = CSI_WRDDR_TYPE_RAW_COMPACT << 11; + else + mask = CSI_WRDDR_TYPE_RAW_UNCOMPACT << 11; + break; + case V4L2_PIX_FMT_SBGGR16: + case V4L2_PIX_FMT_SGBRG16: + case V4L2_PIX_FMT_SGRBG16: + case V4L2_PIX_FMT_SRGGB16: + case V4L2_PIX_FMT_Y16: + mask = CSI_WRDDR_TYPE_RAW_UNCOMPACT << 11; + break; + default: + mask = CSI_WRDDR_TYPE_RAW_COMPACT << 11; + break; + } + return mask; +} + +static int rkcif_stream_start(struct rkcif_stream *stream, unsigned int mode) { u32 val, mbus_flags, href_pol, vsync_pol, xfer_mode = 0, yc_swap = 0, inputmode = 0, @@ -2874,20 +5640,66 @@ multi_id_mode = BT656_1120_MULTI_ID_MODE_1, multi_id_sel = BT656_1120_MULTI_ID_SEL_LSB, bt1120_edge_mode = BT1120_CLOCK_SINGLE_EDGES, - bt1120_flags = 0; + bt1120_flags = 0, + out_fmt_mask = 0, + in_fmt_yuv_order = 0; struct rkmodule_bt656_mbus_info bt1120_info; struct rkcif_device *dev = stream->cifdev; struct rkcif_sensor_info *sensor_info; struct v4l2_mbus_config *mbus; struct rkcif_dvp_sof_subdev *sof_sd = &dev->dvp_sof_subdev; const struct cif_output_fmt *fmt; + unsigned int dma_en = 0; + unsigned int dma_state = 0; + int i = 0; + u32 sav_detect = BT656_DETECT_SAV; + u32 reserved = 0; - if (stream->state != RKCIF_STATE_RESET_IN_STREAMING) + if (stream->state < RKCIF_STATE_STREAMING) { stream->frame_idx = 0; + stream->buf_wake_up_cnt = 0; + stream->lack_buf_cnt = 0; + stream->frame_phase = 0; + stream->is_in_vblank = false; + stream->is_change_toisp = false; + } sensor_info = dev->active_sensor; mbus = &sensor_info->mbus; + dma_state = stream->dma_en; + if ((mode & RKCIF_STREAM_MODE_CAPTURE) == RKCIF_STREAM_MODE_CAPTURE) + stream->dma_en |= RKCIF_DMAEN_BY_VICAP; + else if ((mode & RKCIF_STREAM_MODE_TOISP_RDBK) == RKCIF_STREAM_MODE_TOISP_RDBK) + stream->dma_en |= RKCIF_DMAEN_BY_ISP; + else if ((mode & RKCIF_STREAM_MODE_ROCKIT) == RKCIF_STREAM_MODE_ROCKIT) + stream->dma_en |= RKCIF_DMAEN_BY_ROCKIT; + + if (dma_state) + return 0; + + mbus_flags = mbus->flags; + if ((mbus_flags & CIF_DVP_PCLK_DUAL_EDGE) == CIF_DVP_PCLK_DUAL_EDGE) { + bt1120_edge_mode = (dev->chip_id < CHIP_RK3588_CIF ? + BT1120_CLOCK_DOUBLE_EDGES : BT1120_CLOCK_DOUBLE_EDGES_RK3588); + rkcif_enable_dvp_clk_dual_edge(dev, true); + } else { + bt1120_edge_mode = dev->chip_id < CHIP_RK3588_CIF ? + BT1120_CLOCK_SINGLE_EDGES : BT1120_CLOCK_SINGLE_EDGES_RK3588; + rkcif_enable_dvp_clk_dual_edge(dev, false); + } + + if (IS_ENABLED(CONFIG_CPU_RV1106)) + rkcif_config_dvp_pin(dev, true); + + if (mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + rkcif_config_dvp_clk_sampling_edge(dev, RKCIF_CLK_RISING); + else + rkcif_config_dvp_clk_sampling_edge(dev, RKCIF_CLK_FALLING); + +#if IS_ENABLED(CONFIG_CPU_RV1106) + rv1106_sdmmc_get_lock(); +#endif if (sensor_info->sd && mbus->type == V4L2_MBUS_BT656) { int ret; @@ -2911,32 +5723,21 @@ multi_id_mode = BT656_1120_MULTI_ID_MODE_4; else if (((bt1120_flags & RKMODULE_CAMERA_BT656_CHANNELS) >> 2) > 1) multi_id_mode = BT656_1120_MULTI_ID_MODE_2; - - multi_id = DVP_SW_MULTI_ID(stream->id, stream->id, bt1120_info.id_en_bits); + for (i = 0; i < 4; i++) + multi_id |= DVP_SW_MULTI_ID(i, i, bt1120_info.id_en_bits); rkcif_write_register_or(dev, CIF_REG_DVP_MULTI_ID, multi_id); } } - - mbus_flags = mbus->flags; - if ((mbus_flags & CIF_DVP_PCLK_DUAL_EDGE) == CIF_DVP_PCLK_DUAL_EDGE) { - bt1120_edge_mode = BT1120_CLOCK_DOUBLE_EDGES; - rkcif_enable_dvp_clk_dual_edge(dev, true); - } else { - bt1120_edge_mode = BT1120_CLOCK_SINGLE_EDGES; - rkcif_enable_dvp_clk_dual_edge(dev, false); - } - - if (mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) - rkcif_config_dvp_clk_sampling_edge(dev, RKCIF_CLK_RISING); - else - rkcif_config_dvp_clk_sampling_edge(dev, RKCIF_CLK_FALLING); href_pol = (mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) ? HSY_HIGH_ACTIVE : HSY_LOW_ACTIVE; vsync_pol = (mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) ? VSY_HIGH_ACTIVE : VSY_LOW_ACTIVE; - inputmode = rkcif_determine_input_mode(stream); + if (dev->chip_id < CHIP_RK3588_CIF) + inputmode = rkcif_determine_input_mode(stream); + else + inputmode = rkcif_determine_input_mode_rk3588(stream); if (dev->chip_id <= CHIP_RK1808_CIF) { if (inputmode == INPUT_MODE_BT1120) { if (stream->cif_fmt_in->field == V4L2_FIELD_NONE) @@ -2946,7 +5747,7 @@ if (CIF_FETCH_IS_Y_FIRST(stream->cif_fmt_in->dvp_fmt_val)) yc_swap = BT1120_YC_SWAP; } - } else { + } else if (dev->chip_id < CHIP_RK3588_CIF) { if (sensor_info->mbus.type == V4L2_MBUS_BT656) { if (stream->cif_fmt_in->field == V4L2_FIELD_NONE) xfer_mode = BT1120_TRANSMIT_PROGRESS; @@ -2958,9 +5759,14 @@ if (CIF_FETCH_IS_Y_FIRST(stream->cif_fmt_in->dvp_fmt_val)) yc_swap = BT1120_YC_SWAP; } + } else { + if ((inputmode & INPUT_BT1120_YUV422) == INPUT_BT1120_YUV422) + if (CIF_FETCH_IS_Y_FIRST(stream->cif_fmt_in->dvp_fmt_val)) + yc_swap = BT1120_YC_SWAP_RK3588; } - if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) { + if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY) { inputmode = INPUT_MODE_MIPI; /* if cif is linked with mipi, @@ -2978,33 +5784,43 @@ mipimode = MIPI_MODE_32BITS_BYPASS; } - val = vsync_pol | href_pol | inputmode | mipimode - | stream->cif_fmt_out->fmt_val - | stream->cif_fmt_in->dvp_fmt_val - | xfer_mode | yc_swap | multi_id_en - | multi_id_sel | multi_id_mode | bt1120_edge_mode; - - if (stream->is_high_align) - val |= CIF_HIGH_ALIGN; - else - val &= ~CIF_HIGH_ALIGN; + if (dev->chip_id < CHIP_RK3588_CIF) { + val = vsync_pol | href_pol | inputmode | mipimode + | stream->cif_fmt_out->fmt_val + | stream->cif_fmt_in->dvp_fmt_val + | xfer_mode | yc_swap | multi_id_en + | multi_id_sel | multi_id_mode | bt1120_edge_mode; + if (stream->is_high_align) + val |= CIF_HIGH_ALIGN; + else + val &= ~CIF_HIGH_ALIGN; + } else { + out_fmt_mask = rkcif_dvp_get_output_type_mask(stream); + in_fmt_yuv_order = rkcif_dvp_get_input_yuv_order(stream); + val = vsync_pol | href_pol | inputmode + | yc_swap + | out_fmt_mask + | in_fmt_yuv_order + | multi_id_en + | sav_detect + | multi_id_sel | multi_id_mode | bt1120_edge_mode; + if (stream->is_high_align) + val |= CIF_HIGH_ALIGN_RK3588; + else + val &= ~CIF_HIGH_ALIGN_RK3588; + } rkcif_write_register(dev, CIF_REG_DVP_FOR, val); - val = stream->pixm.width; - if (stream->cif_fmt_in->fmt_type == CIF_FMT_TYPE_RAW) { - fmt = find_output_fmt(stream, stream->pixm.pixelformat); - if (fmt->fourcc == V4L2_PIX_FMT_GREY || - fmt->fourcc == V4L2_PIX_FMT_SRGGB8 || - fmt->fourcc == V4L2_PIX_FMT_SGRBG8 || - fmt->fourcc == V4L2_PIX_FMT_SGBRG8 || - fmt->fourcc == V4L2_PIX_FMT_SBGGR8) + if (dev->chip_id >= CHIP_RK3588_CIF) { + val = stream->pixm.plane_fmt[0].bytesperline; + } else { + fmt = rkcif_find_output_fmt(stream, stream->pixm.pixelformat); + if (fmt->fmt_type == CIF_FMT_TYPE_RAW && + fmt->csi_fmt_val == CSI_WRDDR_TYPE_RAW8) val = ALIGN(stream->pixm.width * fmt->raw_bpp / 8, 256); else val = stream->pixm.width * rkcif_cal_raw_vir_line_ratio(stream, fmt); } - rkcif_write_register(dev, CIF_REG_DVP_VIR_LINE_WIDTH, val); - rkcif_write_register(dev, CIF_REG_DVP_SET_SIZE, - stream->pixm.width | (stream->pixm.height << 16)); if (stream->crop_enable) { dev->channels[stream->id].crop_en = 1; @@ -3020,6 +5836,10 @@ dev->channels[stream->id].crop_en = 0; } + rkcif_write_register(dev, CIF_REG_DVP_VIR_LINE_WIDTH, val); + rkcif_write_register(dev, CIF_REG_DVP_SET_SIZE, + dev->channels[stream->id].width | + (dev->channels[stream->id].height << 16)); rkcif_write_register(dev, CIF_REG_DVP_CROP, dev->channels[stream->id].crop_st_y << CIF_CROP_Y_SHIFT | dev->channels[stream->id].crop_st_x); @@ -3027,17 +5847,44 @@ if (atomic_read(&dev->pipe.stream_cnt) <= 1) rkcif_write_register(dev, CIF_REG_DVP_FRAME_STATUS, FRAME_STAT_CLS); - rkcif_write_register(dev, CIF_REG_DVP_INTSTAT, INTSTAT_CLS); - rkcif_write_register(dev, CIF_REG_DVP_SCL_CTRL, rkcif_scl_ctl(stream)); + if (dev->chip_id < CHIP_RK3588_CIF) { + rkcif_write_register(dev, CIF_REG_DVP_INTSTAT, INTSTAT_CLS); + rkcif_write_register(dev, CIF_REG_DVP_SCL_CTRL, rkcif_scl_ctl(stream)); + rkcif_write_register_or(dev, CIF_REG_DVP_INTEN, + DVP_DMA_END_INTSTAT(stream->id) | + INTSTAT_ERR | PST_INF_FRAME_END); + /* enable line int for sof */ + rkcif_write_register(dev, CIF_REG_DVP_LINE_INT_NUM, 0x1); + rkcif_write_register_or(dev, CIF_REG_DVP_INTEN, LINE_INT_EN); + } else { + if (dev->chip_id == CHIP_RV1106_CIF) + reserved = 0xfc3c0000; + else + reserved = 0; + rkcif_write_register(dev, CIF_REG_DVP_INTSTAT, 0x3c3ffff | reserved); + rkcif_write_register_or(dev, CIF_REG_DVP_INTEN, 0x033ffff);//0x3c3ffff + } - if (dev->chip_id < CHIP_RK1808_CIF) - rkcif_assign_new_buffer_oneframe(stream, - RKCIF_YUV_ADDR_STATE_INIT); - else - rkcif_assign_new_buffer_pingpong(stream, + if (stream->dma_en) { + if (dev->chip_id < CHIP_RK1808_CIF) { + rkcif_assign_new_buffer_oneframe(stream, + RKCIF_YUV_ADDR_STATE_INIT); + } else { + if (mode == RKCIF_STREAM_MODE_CAPTURE) + rkcif_assign_new_buffer_pingpong(stream, RKCIF_YUV_ADDR_STATE_INIT, stream->id); - + else if (mode == RKCIF_STREAM_MODE_TOISP || + mode == RKCIF_STREAM_MODE_TOISP_RDBK) + rkcif_assign_new_buffer_pingpong_toisp(stream, + RKCIF_YUV_ADDR_STATE_INIT, + stream->id); + else if (mode == RKCIF_STREAM_MODE_ROCKIT) + rkcif_assign_new_buffer_pingpong_rockit(stream, + RKCIF_YUV_ADDR_STATE_INIT, + stream->id); + } + } rkcif_write_register_or(dev, CIF_REG_DVP_INTEN, DVP_DMA_END_INTSTAT(stream->id) | INTSTAT_ERR | PST_INF_FRAME_END); @@ -3053,14 +5900,47 @@ else workmode = MODE_LINELOOP; - if (inputmode == INPUT_MODE_BT1120) { + if ((inputmode & INPUT_MODE_BT1120) == INPUT_MODE_BT1120) { workmode = MODE_PINGPONG; dev->workmode = RKCIF_WORKMODE_PINGPONG; } - rkcif_write_register(dev, CIF_REG_DVP_CTRL, - AXI_BURST_16 | workmode | ENABLE_CAPTURE); - + if (dev->chip_id == CHIP_RK3588_CIF) { + if (stream->dma_en) + dma_en = DVP_DMA_EN; + if (stream->lack_buf_cnt == 2) + dma_en = 0; + rkcif_write_register(dev, CIF_REG_DVP_CTRL, + DVP_SW_WATER_LINE_25 + | dma_en + | DVP_PRESS_EN + | DVP_HURRY_EN + | DVP_SW_WATER_LINE_25 + | DVP_SW_PRESS_VALUE(3) + | DVP_SW_HURRY_VALUE(3) + | ENABLE_CAPTURE); + } else if (dev->chip_id == CHIP_RV1106_CIF) { + if (stream->dma_en) + dma_en = DVP_SW_DMA_EN(stream->id); + if (stream->lack_buf_cnt == 2) + dma_en = 0; + rkcif_write_register(dev, CIF_REG_DVP_CTRL, + DVP_SW_WATER_LINE_25 + | DVP_PRESS_EN + | DVP_HURRY_EN + | DVP_SW_WATER_LINE_25 + | DVP_SW_PRESS_VALUE(3) + | DVP_SW_HURRY_VALUE(3) + | DVP_SW_CAP_EN(stream->id) + | dma_en + | ENABLE_CAPTURE); + } else { + rkcif_write_register(dev, CIF_REG_DVP_CTRL, + AXI_BURST_16 | workmode | ENABLE_CAPTURE); + } +#if IS_ENABLED(CONFIG_CPU_RV1106) + rv1106_sdmmc_put_lock(); +#endif atomic_set(&sof_sd->frm_sync_seq, 0); stream->state = RKCIF_STATE_STREAMING; stream->cifdev->dvp_sof_in_oneframe = 0; @@ -3068,34 +5948,198 @@ return 0; } -static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count) +static void rkcif_attach_sync_mode(struct rkcif_device *cifdev) { - struct rkcif_stream *stream = queue->drv_priv; + struct rkcif_hw *hw = cifdev->hw_dev; + struct rkcif_device *dev; + struct sditf_priv *priv; + int i = 0, j = 0; + int ret = 0; + int count = 0; + int sync_type = NO_SYNC_MODE; + int sync_group = 0; + struct rkcif_sync_cfg sync_cfg; + struct rkcif_multi_sync_config *sync_config; + + mutex_lock(&hw->dev_lock); + if (cifdev->sditf_cnt <= 1) { + ret = v4l2_subdev_call(cifdev->terminal_sensor.sd, + core, ioctl, + RKMODULE_GET_SYNC_MODE, + &sync_type); + if (!ret) + sync_cfg.type = sync_type; + else + sync_cfg.type = NO_SYNC_MODE; + ret = v4l2_subdev_call(cifdev->terminal_sensor.sd, + core, ioctl, + RKMODULE_GET_GROUP_ID, + &sync_group); + if (!ret && sync_group < RKCIF_MAX_GROUP) + sync_cfg.group = sync_group; + else + sync_cfg.group = 0; + } else { + for (j = 0; j < cifdev->sditf_cnt; j++) { + ret |= v4l2_subdev_call(cifdev->sditf[j]->sensor_sd, + core, ioctl, + RKMODULE_GET_SYNC_MODE, + &sync_type); + if (!ret && sync_type) + break; + } + if (!ret) + sync_cfg.type = sync_type; + else + sync_cfg.type = NO_SYNC_MODE; + ret = v4l2_subdev_call(cifdev->sditf[j]->sensor_sd, + core, ioctl, + RKMODULE_GET_GROUP_ID, + &sync_group); + if (!ret && sync_group < RKCIF_MAX_GROUP) + sync_cfg.group = sync_group; + else + sync_cfg.group = 0; + } + cifdev->sync_cfg = sync_cfg; + if (sync_cfg.type == NO_SYNC_MODE || + hw->sync_config[sync_cfg.group].is_attach) { + mutex_unlock(&hw->dev_lock); + return; + } + + sync_config = &hw->sync_config[sync_cfg.group]; + memset(sync_config, 0, sizeof(struct rkcif_multi_sync_config)); + for (i = 0; i < hw->dev_num; i++) { + dev = hw->cif_dev[i]; + if (dev->sditf_cnt <= 1) { + ret = v4l2_subdev_call(dev->terminal_sensor.sd, + core, ioctl, + RKMODULE_GET_SYNC_MODE, + &sync_type); + if (!ret) + sync_cfg.type = sync_type; + else + sync_cfg.type = NO_SYNC_MODE; + ret = v4l2_subdev_call(dev->terminal_sensor.sd, + core, ioctl, + RKMODULE_GET_GROUP_ID, + &sync_group); + if (!ret && sync_group < RKCIF_MAX_GROUP) + sync_cfg.group = sync_group; + else + sync_cfg.group = 0; + } else { + priv = dev->sditf[0]; + if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF) { + for (j = 0; j < dev->sditf_cnt; j++) { + ret |= v4l2_subdev_call(dev->sditf[j]->sensor_sd, + core, ioctl, + RKMODULE_GET_SYNC_MODE, + &sync_type); + if (!ret && sync_type) { + priv = dev->sditf[j]; + break; + } + } + if (!ret) + sync_cfg.type = sync_type; + else + sync_cfg.type = NO_SYNC_MODE; + ret = v4l2_subdev_call(priv->sensor_sd, + core, ioctl, + RKMODULE_GET_GROUP_ID, + &sync_group); + if (!ret && sync_group < RKCIF_MAX_GROUP) + sync_cfg.group = sync_group; + else + sync_cfg.group = 0; + } + } + if (sync_cfg.group == cifdev->sync_cfg.group) { + if (sync_cfg.type == EXTERNAL_MASTER_MODE) { + count = sync_config->ext_master.count; + sync_config->ext_master.cif_dev[count] = dev; + sync_config->ext_master.count++; + sync_config->dev_cnt++; + sync_config->sync_mask |= BIT(dev->csi_host_idx); + } else if (sync_cfg.type == INTERNAL_MASTER_MODE) { + count = sync_config->int_master.count; + sync_config->int_master.cif_dev[count] = dev; + sync_config->int_master.count++; + sync_config->dev_cnt++; + sync_config->sync_mask |= BIT(dev->csi_host_idx); + } else if (sync_cfg.type == SLAVE_MODE) { + count = sync_config->slave.count; + sync_config->slave.cif_dev[count] = dev; + sync_config->slave.count++; + sync_config->dev_cnt++; + sync_config->sync_mask |= BIT(dev->csi_host_idx); + } + dev->sync_cfg = sync_cfg; + } else { + ret = v4l2_subdev_call(dev->terminal_sensor.sd, + core, ioctl, + RKMODULE_GET_SYNC_MODE, + &sync_type); + } + } + if (sync_config->int_master.count == 1) { + if (sync_config->ext_master.count) { + sync_config->mode = RKCIF_MASTER_MASTER; + sync_config->is_attach = true; + } else if (sync_config->slave.count) { + sync_config->mode = RKCIF_MASTER_SLAVE; + sync_config->is_attach = true; + } else { + dev_info(hw->dev, + "Missing slave device, do not use sync mode\n"); + } + if (sync_config->is_attach) + dev_info(hw->dev, + "group %d, int_master %d, ext_master %d, slave %d\n", + i, + sync_config->int_master.count, + sync_config->ext_master.count, + sync_config->slave.count); + } + mutex_unlock(&hw->dev_lock); +} + +static void rkcif_monitor_reset_event(struct rkcif_device *dev); + +int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) +{ struct rkcif_vdev_node *node = &stream->vnode; struct rkcif_device *dev = stream->cifdev; + struct rkcif_hw *hw_dev = dev->hw_dev; struct v4l2_device *v4l2_dev = &dev->v4l2_dev; struct rkcif_sensor_info *sensor_info = dev->active_sensor; - struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor; + struct rkcif_sensor_info *terminal_sensor = NULL; struct rkmodule_hdr_cfg hdr_cfg; + struct rkcif_csi_info csi_info = {0}; int rkmodule_stream_seq = RKMODULE_START_STREAM_DEFAULT; int ret; + int i = 0; v4l2_info(&dev->v4l2_dev, "stream[%d] start streaming\n", stream->id); - mutex_lock(&dev->hw_dev->dev_lock); + rkcif_attach_sync_mode(dev); + mutex_lock(&dev->stream_lock); - if (WARN_ON(stream->state != RKCIF_STATE_READY)) { + if ((stream->cur_stream_mode & RKCIF_STREAM_MODE_CAPTURE) == mode) { ret = -EBUSY; v4l2_err(v4l2_dev, "stream in busy state\n"); goto destroy_buf; } + if (stream->dma_en == 0) + stream->fs_cnt_in_single_frame = 0; if (stream->is_line_wake_up) stream->is_line_inten = true; else stream->is_line_inten = false; - stream->fs_cnt_in_single_frame = 0; - if (dev->active_sensor) { + if (!dev->active_sensor) { ret = rkcif_update_sensor_info(stream); if (ret < 0) { v4l2_err(v4l2_dev, @@ -3104,16 +6148,16 @@ goto out; } } - + terminal_sensor = &dev->terminal_sensor; if (terminal_sensor->sd) { ret = v4l2_subdev_call(terminal_sensor->sd, core, ioctl, RKMODULE_GET_HDR_CFG, &hdr_cfg); if (!ret) - dev->hdr.mode = hdr_cfg.hdr_mode; + dev->hdr = hdr_cfg; else - dev->hdr.mode = NO_HDR; + dev->hdr.hdr_mode = NO_HDR; ret = v4l2_subdev_call(terminal_sensor->sd, video, g_frame_interval, &terminal_sensor->fi); @@ -3134,102 +6178,149 @@ if (ret < 0) goto destroy_buf; + mutex_lock(&hw_dev->dev_lock); + if (atomic_read(&dev->pipe.stream_cnt) == 0 && + dev->active_sensor && + (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY || + dev->active_sensor->mbus.type == V4L2_MBUS_CCP2)) { + if (dev->channels[0].capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + csi_info.csi_num = dev->channels[0].capture_info.multi_dev.dev_num; + if (csi_info.csi_num > RKCIF_MAX_CSI_NUM) { + v4l2_err(v4l2_dev, + "csi num %d, max %d\n", + csi_info.csi_num, RKCIF_MAX_CSI_NUM); + goto out; + } + for (i = 0; i < csi_info.csi_num; i++) { + csi_info.csi_idx[i] = dev->channels[0].capture_info.multi_dev.dev_idx[i]; + if (dev->hw_dev->is_rk3588s2) + v4l2_info(v4l2_dev, "rk3588s2 combine mode attach to mipi%d\n", + csi_info.csi_idx[i]); + } + } else { + csi_info.csi_num = 1; + dev->csi_host_idx = dev->csi_host_idx_def; + csi_info.csi_idx[0] = dev->csi_host_idx; + } + ret = v4l2_subdev_call(dev->active_sensor->sd, + core, ioctl, + RKCIF_CMD_SET_CSI_IDX, + &csi_info); + if (ret) + v4l2_err(&dev->v4l2_dev, "set csi idx %d fail\n", dev->csi_host_idx); + + } + if (((dev->active_sensor && dev->active_sensor->mbus.type == V4L2_MBUS_BT656) || dev->is_use_dummybuf) && - (!dev->dummy_buf.vaddr)) { + (!dev->hw_dev->dummy_buf.vaddr) && + mode == RKCIF_STREAM_MODE_CAPTURE) { ret = rkcif_create_dummy_buf(stream); if (ret < 0) { + mutex_unlock(&hw_dev->dev_lock); v4l2_err(v4l2_dev, "Failed to create dummy_buf, %d\n", ret); goto destroy_buf; } } + mutex_unlock(&hw_dev->dev_lock); - ret = dev->pipe.open(&dev->pipe, &node->vdev.entity, true); - if (ret < 0) { - v4l2_err(v4l2_dev, "open cif pipeline failed %d\n", - ret); - goto destroy_buf; + if (mode == RKCIF_STREAM_MODE_CAPTURE) + tasklet_enable(&stream->vb_done_tasklet); + + if (stream->cur_stream_mode == RKCIF_STREAM_MODE_NONE) { + ret = dev->pipe.open(&dev->pipe, &node->vdev.entity, true); + if (ret < 0) { + v4l2_err(v4l2_dev, "open cif pipeline failed %d\n", + ret); + goto destroy_buf; + } + + /* + * start sub-devices + * When use bt601, the sampling edge of cif is random, + * can be rising or fallling after powering on cif. + * To keep the coherence of edge, open sensor in advance. + */ + if (sensor_info->mbus.type == V4L2_MBUS_PARALLEL || + rkmodule_stream_seq == RKMODULE_START_STREAM_FRONT) { + ret = dev->pipe.set_stream(&dev->pipe, true); + if (ret < 0) + goto destroy_buf; + } } - - /* - * start sub-devices - * When use bt601, the sampling edge of cif is random, - * can be rising or fallling after powering on cif. - * To keep the coherence of edge, open sensor in advance. - */ - if (sensor_info->mbus.type == V4L2_MBUS_PARALLEL || - rkmodule_stream_seq == RKMODULE_START_STREAM_FRONT) { - ret = dev->pipe.set_stream(&dev->pipe, true); - if (ret < 0) - goto runtime_put; - } - if (dev->chip_id >= CHIP_RK1808_CIF) { - if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2 || - dev->active_sensor->mbus.type == V4L2_MBUS_CCP2) - ret = rkcif_csi_stream_start(stream); + if (dev->active_sensor && + (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY || + dev->active_sensor->mbus.type == V4L2_MBUS_CCP2)) + ret = rkcif_csi_stream_start(stream, mode); else - ret = rkcif_stream_start(stream); + ret = rkcif_stream_start(stream, mode); } else { - ret = rkcif_stream_start(stream); + ret = rkcif_stream_start(stream, mode); } if (ret < 0) - goto runtime_put; + goto destroy_buf; - ret = media_pipeline_start(&node->vdev.entity, &dev->pipe.pipe); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "start pipeline failed %d\n", - ret); - goto pipe_stream_off; + if (stream->cur_stream_mode == RKCIF_STREAM_MODE_NONE) { + ret = media_pipeline_start(&node->vdev.entity, &dev->pipe.pipe); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "start pipeline failed %d\n", + ret); + goto pipe_stream_off; + } + + if (sensor_info->mbus.type != V4L2_MBUS_PARALLEL && + rkmodule_stream_seq != RKMODULE_START_STREAM_FRONT) { + ret = dev->pipe.set_stream(&dev->pipe, true); + if (ret < 0) + goto stop_stream; + } } - - if (sensor_info->mbus.type != V4L2_MBUS_PARALLEL && - rkmodule_stream_seq != RKMODULE_START_STREAM_FRONT) { - ret = dev->pipe.set_stream(&dev->pipe, true); - if (ret < 0) - goto stop_stream; - } - - if (dev->hdr.mode == NO_HDR) { - if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_STREAMING) { - rkcif_start_luma(&dev->luma_vdev, + if (dev->chip_id == CHIP_RV1126_CIF || + dev->chip_id == CHIP_RV1126_CIF_LITE || + dev->chip_id == CHIP_RK3568_CIF) { + if (dev->hdr.hdr_mode == NO_HDR) { + if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_STREAMING) + rkcif_start_luma(&dev->luma_vdev, + dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in); + } else if (dev->hdr.hdr_mode == HDR_X2) { + if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_STREAMING && + dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_STREAMING) + rkcif_start_luma(&dev->luma_vdev, + dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in); + } else if (dev->hdr.hdr_mode == HDR_X3) { + if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_STREAMING && + dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_STREAMING && + dev->stream[RKCIF_STREAM_MIPI_ID2].state == RKCIF_STATE_STREAMING) + rkcif_start_luma(&dev->luma_vdev, dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in); } - } else if (dev->hdr.mode == HDR_X2) { - if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_STREAMING && - dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_STREAMING) { - rkcif_start_luma(&dev->luma_vdev, - dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in); - } - } else if (dev->hdr.mode == HDR_X3) { - if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_STREAMING && - dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_STREAMING && - dev->stream[RKCIF_STREAM_MIPI_ID2].state == RKCIF_STATE_STREAMING) { - rkcif_start_luma(&dev->luma_vdev, - dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in); - } } - - if (dev->hw_dev->reset_work_cancel) - dev->hw_dev->reset_work_cancel = false; - if (dev->hdr.mode == NO_HDR) - stream->streamon_timestamp = ktime_get_ns(); + dev->reset_work_cancel = false; + stream->cur_stream_mode |= mode; + rkcif_monitor_reset_event(dev); goto out; stop_stream: rkcif_stream_stop(stream); pipe_stream_off: dev->pipe.set_stream(&dev->pipe, false); -runtime_put: - pm_runtime_put_sync(dev->dev); + destroy_buf: - if (stream->next_buf) - vb2_buffer_done(&stream->next_buf->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); + if (mode == RKCIF_STREAM_MODE_CAPTURE) + tasklet_disable(&stream->vb_done_tasklet); if (stream->curr_buf) - vb2_buffer_done(&stream->curr_buf->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); + list_add_tail(&stream->curr_buf->queue, &stream->buf_head); + if (stream->next_buf && + stream->next_buf != stream->curr_buf) + list_add_tail(&stream->next_buf->queue, &stream->buf_head); + + stream->curr_buf = NULL; + stream->next_buf = NULL; + atomic_set(&stream->buf_cnt, 0); while (!list_empty(&stream->buf_head)) { struct rkcif_buffer *buf; @@ -3240,7 +6331,16 @@ } out: - mutex_unlock(&dev->hw_dev->dev_lock); + mutex_unlock(&dev->stream_lock); + return ret; +} + +static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count) +{ + struct rkcif_stream *stream = queue->drv_priv; + int ret = 0; + + ret = rkcif_do_start_stream(stream, RKCIF_STREAM_MODE_CAPTURE); return ret; } @@ -3263,10 +6363,7 @@ q->io_modes = VB2_MMAP | VB2_DMABUF; q->drv_priv = stream; q->ops = &rkcif_vb2_ops; - if (hw_dev->iommu_en) - q->mem_ops = &vb2_dma_sg_memops; - else - q->mem_ops = &vb2_dma_contig_memops; + q->mem_ops = hw_dev->mem_ops; q->buf_struct_size = sizeof(struct rkcif_buffer); if (stream->cifdev->is_use_dummybuf) q->min_buffers_needed = 1; @@ -3278,14 +6375,17 @@ q->allow_cache_hints = 1; q->bidirectional = 1; q->gfp_flags = GFP_DMA32; + if (hw_dev->is_dma_contig) + q->dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS; return vb2_queue_init(q); } -static void rkcif_set_fmt(struct rkcif_stream *stream, - struct v4l2_pix_format_mplane *pixm, - bool try) +int rkcif_set_fmt(struct rkcif_stream *stream, + struct v4l2_pix_format_mplane *pixm, + bool try) { struct rkcif_device *dev = stream->cifdev; + struct sditf_priv *priv = dev->sditf[0]; const struct cif_output_fmt *fmt; const struct cif_input_fmt *cif_fmt_in = NULL; struct v4l2_rect input_rect; @@ -3293,9 +6393,13 @@ u32 xsubs = 1, ysubs = 1, i; struct rkmodule_hdr_cfg hdr_cfg; struct rkcif_extend_info *extend_line = &stream->extend_line; - int ret, vc; + struct csi_channel_info *channel_info = &dev->channels[stream->id]; + int ret; - fmt = find_output_fmt(stream, pixm->pixelformat); + for (i = 0; i < RKCIF_MAX_PLANE; i++) + memset(&pixm->plane_fmt[i], 0, sizeof(struct v4l2_plane_pix_format)); + + fmt = rkcif_find_output_fmt(stream, pixm->pixelformat); if (!fmt) fmt = &out_fmts[0]; @@ -3303,10 +6407,19 @@ input_rect.height = RKCIF_DEFAULT_HEIGHT; if (dev->terminal_sensor.sd) { - cif_fmt_in = get_input_fmt(dev->terminal_sensor.sd, - &input_rect, stream->id, &vc); + cif_fmt_in = rkcif_get_input_fmt(dev, + &input_rect, stream->id, + channel_info); stream->cif_fmt_in = cif_fmt_in; + } else { + v4l2_err(&stream->cifdev->v4l2_dev, + "terminal subdev does not exist\n"); + return -EINVAL; } + + ret = rkcif_output_fmt_check(stream, fmt); + if (ret) + return -EINVAL; if (dev->terminal_sensor.sd) { ret = v4l2_subdev_call(dev->terminal_sensor.sd, @@ -3314,9 +6427,9 @@ RKMODULE_GET_HDR_CFG, &hdr_cfg); if (!ret) - dev->hdr.mode = hdr_cfg.hdr_mode; + dev->hdr = hdr_cfg; else - dev->hdr.mode = NO_HDR; + dev->hdr.hdr_mode = NO_HDR; dev->terminal_sensor.raw_rect = input_rect; } @@ -3337,6 +6450,11 @@ fcc_xysubs(fmt->fourcc, &xsubs, &ysubs); planes = fmt->cplanes ? fmt->cplanes : fmt->mplanes; + + if (cif_fmt_in && + (cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8 || + cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8)) + stream->crop_enable = false; for (i = 0; i < planes; i++) { struct v4l2_plane_pix_format *plane_fmt; @@ -3360,6 +6478,9 @@ } } + if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF) + height *= dev->sditf_cnt; + extend_line->pixm.height = height + RKMODULE_EXTEND_LINE; /* compact mode need bytesperline 4bytes align, @@ -3367,25 +6488,29 @@ * to optimize reading and writing of ddr, aliged with 256. */ if (fmt->fmt_type == CIF_FMT_TYPE_RAW && - (stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8 || - stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8)) { + cif_fmt_in && + (cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8 || + cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8)) { stream->is_compact = false; } if (fmt->fmt_type == CIF_FMT_TYPE_RAW && stream->is_compact && - (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2 || + (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY || dev->active_sensor->mbus.type == V4L2_MBUS_CCP2) && - fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888) { - bpl = ALIGN(width * fmt->raw_bpp / 8, 256); - } else if (fmt->fourcc == V4L2_PIX_FMT_GREY || - fmt->fourcc == V4L2_PIX_FMT_SRGGB8 || - fmt->fourcc == V4L2_PIX_FMT_SGRBG8 || - fmt->fourcc == V4L2_PIX_FMT_SGBRG8 || - fmt->fourcc == V4L2_PIX_FMT_SBGGR8) { + fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888 && + fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB565) { bpl = ALIGN(width * fmt->raw_bpp / 8, 256); } else { - bpp = rkcif_align_bits_per_pixel(stream, fmt, i); - bpl = width * bpp / CIF_YUV_STORED_BIT_WIDTH; + if (fmt->fmt_type == CIF_FMT_TYPE_RAW && stream->is_compact && + fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888 && + fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB565 && + dev->chip_id >= CHIP_RK3588_CIF) { + bpl = ALIGN(width * fmt->raw_bpp / 8, 256); + } else { + bpp = rkcif_align_bits_per_pixel(stream, fmt, i); + bpl = width * bpp / CIF_YUV_STORED_BIT_WIDTH; + } } size = bpl * height; imagesize += size; @@ -3425,6 +6550,7 @@ pixm->width, pixm->height, stream->pixm.width, stream->pixm.height); } + return 0; } void rkcif_stream_init(struct rkcif_device *dev, u32 id) @@ -3439,6 +6565,9 @@ stream->cifdev = dev; INIT_LIST_HEAD(&stream->buf_head); + INIT_LIST_HEAD(&stream->rx_buf_head); + INIT_LIST_HEAD(&stream->rx_buf_head_vicap); + INIT_LIST_HEAD(&stream->rockit_buf_head); spin_lock_init(&stream->vbq_lock); spin_lock_init(&stream->fps_lock); stream->state = RKCIF_STATE_READY; @@ -3474,6 +6603,8 @@ } stream->is_high_align = false; + stream->is_finish_stop_dma = false; + stream->is_wait_dma_stop = false; if (dev->chip_id == CHIP_RV1126_CIF || dev->chip_id == CHIP_RV1126_CIF_LITE) @@ -3493,7 +6624,15 @@ dev->wait_line_cache = 0; dev->wait_line_bak = 0; } - + stream->cur_stream_mode = 0; + stream->dma_en = 0; + stream->to_en_dma = 0; + stream->to_stop_dma = 0; + stream->to_en_scale = false; + stream->buf_owner = 0; + stream->buf_replace_cnt = 0; + stream->is_stop_capture = false; + atomic_set(&stream->buf_cnt, 0); } static int rkcif_fh_open(struct file *filp) @@ -3503,6 +6642,7 @@ struct rkcif_stream *stream = to_rkcif_stream(vnode); struct rkcif_device *cifdev = stream->cifdev; int ret; + int i = 0; ret = rkcif_attach_hw(cifdev); if (ret) @@ -3518,38 +6658,35 @@ return ret; } - /* enable clocks/power-domains */ - ret = pm_runtime_get_sync(cifdev->dev); + ret = pm_runtime_resume_and_get(cifdev->dev); if (ret < 0) { v4l2_err(vdev, "Failed to get runtime pm, %d\n", ret); return ret; } - /* - * Soft reset via CRU. - * Because CRU would reset iommu too, so there's not chance - * to reset cif once we hold buffers after buf queued - */ - if (cifdev->chip_id == CHIP_RK1808_CIF || - cifdev->chip_id == CHIP_RV1126_CIF || - cifdev->chip_id == CHIP_RV1126_CIF_LITE || - cifdev->chip_id == CHIP_RK3568_CIF) { - mutex_lock(&cifdev->stream_lock); - if (!atomic_read(&cifdev->fh_cnt)) - rkcif_soft_reset(cifdev, true); - atomic_inc(&cifdev->fh_cnt); - mutex_unlock(&cifdev->stream_lock); - } else { - rkcif_soft_reset(cifdev, true); - } ret = v4l2_fh_open(filp); if (!ret) { - ret = v4l2_pipeline_pm_use(&vnode->vdev.entity, 1); + mutex_lock(&cifdev->stream_lock); + ret = v4l2_pipeline_pm_get(&vnode->vdev.entity); + v4l2_info(vdev, "open video, entity use_countt %d\n", + vnode->vdev.entity.use_count); + mutex_unlock(&cifdev->stream_lock); if (ret < 0) vb2_fop_release(filp); } - + if (cifdev->sditf_cnt > 1) { + for (i = 0; i < cifdev->sditf_cnt; i++) { + if (cifdev->sditf[i]->sensor_sd) + ret |= v4l2_subdev_call(cifdev->sditf[i]->sensor_sd, + core, + s_power, + 1); + } + if (ret < 0) + v4l2_err(vdev, "set sensor power on fail, ret %d\n", + ret); + } return ret; } @@ -3560,23 +6697,30 @@ struct rkcif_stream *stream = to_rkcif_stream(vnode); struct rkcif_device *cifdev = stream->cifdev; int ret = 0; + int i = 0; ret = vb2_fop_release(filp); if (!ret) { - ret = v4l2_pipeline_pm_use(&vnode->vdev.entity, 0); - if (ret < 0) - v4l2_err(&cifdev->v4l2_dev, - "set pipeline power failed %d\n", ret); + mutex_lock(&cifdev->stream_lock); + v4l2_pipeline_pm_put(&vnode->vdev.entity); + v4l2_info(vdev, "close video, entity use_count %d\n", + vnode->vdev.entity.use_count); + mutex_unlock(&cifdev->stream_lock); } - mutex_lock(&cifdev->stream_lock); - if (!atomic_dec_return(&cifdev->fh_cnt)) - rkcif_soft_reset(cifdev, true); - else if (atomic_read(&cifdev->fh_cnt) < 0) - atomic_set(&cifdev->fh_cnt, 0); - mutex_unlock(&cifdev->stream_lock); pm_runtime_put_sync(cifdev->dev); - + if (cifdev->sditf_cnt > 1) { + for (i = 0; i < cifdev->sditf_cnt; i++) { + if (cifdev->sditf[i]->sensor_sd) + ret |= v4l2_subdev_call(cifdev->sditf[i]->sensor_sd, + core, + s_power, + 0); + } + if (ret < 0) + v4l2_err(vdev, "set sensor power on fail, ret %d\n", + ret); + } return ret; } @@ -3607,41 +6751,50 @@ struct v4l2_format *f) { struct rkcif_stream *stream = video_drvdata(file); + int ret = 0; - rkcif_set_fmt(stream, &f->fmt.pix_mp, true); + ret = rkcif_set_fmt(stream, &f->fmt.pix_mp, true); - return 0; + return ret; } static int rkcif_enum_framesizes(struct file *file, void *prov, struct v4l2_frmsizeenum *fsize) { + struct v4l2_frmsize_discrete *d = &fsize->discrete; struct v4l2_frmsize_stepwise *s = &fsize->stepwise; struct rkcif_stream *stream = video_drvdata(file); struct rkcif_device *dev = stream->cifdev; struct v4l2_rect input_rect; - int vc; + struct csi_channel_info csi_info; if (fsize->index != 0) return -EINVAL; - if (!find_output_fmt(stream, fsize->pixel_format)) + if (!rkcif_find_output_fmt(stream, fsize->pixel_format)) return -EINVAL; input_rect.width = RKCIF_DEFAULT_WIDTH; input_rect.height = RKCIF_DEFAULT_HEIGHT; if (dev->terminal_sensor.sd) - get_input_fmt(dev->terminal_sensor.sd, - &input_rect, stream->id, &vc); + rkcif_get_input_fmt(dev, + &input_rect, stream->id, + &csi_info); - fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - s->min_width = CIF_MIN_WIDTH; - s->min_height = CIF_MIN_HEIGHT; - s->max_width = input_rect.width; - s->max_height = input_rect.height; - s->step_width = OUTPUT_STEP_WISE; - s->step_height = OUTPUT_STEP_WISE; + if (dev->hw_dev->adapt_to_usbcamerahal) { + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + d->width = input_rect.width; + d->height = input_rect.height; + } else { + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + s->min_width = CIF_MIN_WIDTH; + s->min_height = CIF_MIN_HEIGHT; + s->max_width = input_rect.width; + s->max_height = input_rect.height; + s->step_width = OUTPUT_STEP_WISE; + s->step_height = OUTPUT_STEP_WISE; + } return 0; } @@ -3673,13 +6826,19 @@ fi.interval.denominator = 30; } - fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; - fival->stepwise.step.numerator = 1; - fival->stepwise.step.denominator = 1; - fival->stepwise.max.numerator = 1; - fival->stepwise.max.denominator = 1; - fival->stepwise.min.numerator = fi.interval.numerator; - fival->stepwise.min.denominator = fi.interval.denominator; + if (dev->hw_dev->adapt_to_usbcamerahal) { + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete.numerator = fi.interval.numerator; + fival->discrete.denominator = fi.interval.denominator; + } else { + fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; + fival->stepwise.step.numerator = 1; + fival->stepwise.step.denominator = 1; + fival->stepwise.max.numerator = 1; + fival->stepwise.max.denominator = 1; + fival->stepwise.min.numerator = fi.interval.numerator; + fival->stepwise.min.denominator = fi.interval.denominator; + } return 0; } @@ -3688,13 +6847,57 @@ struct v4l2_fmtdesc *f) { const struct cif_output_fmt *fmt = NULL; + struct rkcif_stream *stream = video_drvdata(file); + struct rkcif_device *dev = stream->cifdev; + const struct cif_input_fmt *cif_fmt_in = NULL; + struct v4l2_rect input_rect; + int i = 0; + int ret = 0; + int fource_idx = 0; if (f->index >= ARRAY_SIZE(out_fmts)) return -EINVAL; - fmt = &out_fmts[f->index]; - f->pixelformat = fmt->fourcc; + if (dev->terminal_sensor.sd) { + cif_fmt_in = rkcif_get_input_fmt(dev, + &input_rect, stream->id, + &dev->channels[stream->id]); + stream->cif_fmt_in = cif_fmt_in; + } else { + v4l2_err(&stream->cifdev->v4l2_dev, + "terminal subdev does not exist\n"); + return -EINVAL; + } + if (f->index != 0) + fource_idx = stream->new_fource_idx; + + for (i = fource_idx; i < ARRAY_SIZE(out_fmts); i++) { + fmt = &out_fmts[i]; + ret = rkcif_output_fmt_check(stream, fmt); + if (!ret) { + f->pixelformat = fmt->fourcc; + stream->new_fource_idx = i + 1; + break; + } + } + if (i == ARRAY_SIZE(out_fmts)) + return -EINVAL; + + switch (f->pixelformat) { + case V4l2_PIX_FMT_EBD8: + strscpy(f->description, + "Embedded data 8-bit", + sizeof(f->description)); + break; + case V4l2_PIX_FMT_SPD16: + strscpy(f->description, + "Shield pix data 16-bit", + sizeof(f->description)); + break; + default: + break; + } return 0; } @@ -3703,15 +6906,16 @@ { struct rkcif_stream *stream = video_drvdata(file); struct rkcif_device *dev = stream->cifdev; + int ret = 0; if (vb2_is_busy(&stream->vnode.buf_queue)) { v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__); return -EBUSY; } - rkcif_set_fmt(stream, &f->fmt.pix_mp, false); + ret = rkcif_set_fmt(stream, &f->fmt.pix_mp, false); - return 0; + return ret; } static int rkcif_g_fmt_vid_cap_mplane(struct file *file, void *fh, @@ -3738,8 +6942,8 @@ return 0; } -static int rkcif_cropcap(struct file *file, void *fh, - struct v4l2_cropcap *cap) +static __maybe_unused int rkcif_cropcap(struct file *file, void *fh, + struct v4l2_cropcap *cap) { struct rkcif_stream *stream = video_drvdata(file); struct rkcif_device *dev = stream->cifdev; @@ -3765,78 +6969,16 @@ return ret; } -static int rkcif_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) -{ - struct rkcif_stream *stream = video_drvdata(file); - struct rkcif_device *dev = stream->cifdev; - const struct v4l2_rect *rect = &a->c; - struct v4l2_rect sensor_crop; - struct v4l2_rect *raw_rect = &dev->terminal_sensor.raw_rect; - int ret; - - ret = rkcif_sanity_check_fmt(stream, rect); - if (ret) { - v4l2_err(&dev->v4l2_dev, "set crop failed\n"); - return ret; - } - - if (stream->crop_mask & CROP_SRC_SENSOR) { - sensor_crop = stream->crop[CROP_SRC_SENSOR]; - if (rect->left + rect->width > sensor_crop.width || - rect->top + rect->height > sensor_crop.height) { - v4l2_err(&dev->v4l2_dev, - "crop size is bigger than sensor input:left:%d, top:%d, width:%d, height:%d\n", - sensor_crop.left, sensor_crop.top, sensor_crop.width, sensor_crop.height); - return -EINVAL; - } - } else { - if (rect->left + rect->width > raw_rect->width || - rect->top + rect->height > raw_rect->height) { - v4l2_err(&dev->v4l2_dev, - "crop size is bigger than sensor raw input:left:%d, top:%d, width:%d, height:%d\n", - raw_rect->left, raw_rect->top, raw_rect->width, raw_rect->height); - return -EINVAL; - } - } - - stream->crop[CROP_SRC_USR] = *rect; - stream->crop_enable = true; - stream->crop_mask |= CROP_SRC_USR_MASK; - stream->crop[CROP_SRC_ACT] = stream->crop[CROP_SRC_USR]; - if (stream->crop_mask & CROP_SRC_SENSOR) { - stream->crop[CROP_SRC_ACT].left = sensor_crop.left + stream->crop[CROP_SRC_USR].left; - stream->crop[CROP_SRC_ACT].top = sensor_crop.top + stream->crop[CROP_SRC_USR].top; - } - - if (stream->state == RKCIF_STATE_STREAMING) { - stream->crop_dyn_en = true; - - v4l2_info(&dev->v4l2_dev, "enable dynamic crop, S_CROP(%ux%u@%u:%u) type: %d\n", - rect->width, rect->height, rect->left, rect->top, a->type); - } else { - v4l2_info(&dev->v4l2_dev, "static crop, S_CROP(%ux%u@%u:%u) type: %d\n", - rect->width, rect->height, rect->left, rect->top, a->type); - } - - return ret; -} - -static int rkcif_g_crop(struct file *file, void *fh, struct v4l2_crop *a) -{ - struct rkcif_stream *stream = video_drvdata(file); - - a->c = stream->crop[CROP_SRC_ACT]; - - return 0; -} - static int rkcif_s_selection(struct file *file, void *fh, - struct v4l2_selection *s) + struct v4l2_selection *s) { struct rkcif_stream *stream = video_drvdata(file); struct rkcif_device *dev = stream->cifdev; struct v4l2_subdev *sensor_sd; struct v4l2_subdev_selection sd_sel; + const struct v4l2_rect *rect = &s->r; + struct v4l2_rect sensor_crop; + struct v4l2_rect *raw_rect = &dev->terminal_sensor.raw_rect; u16 pad = 0; int ret = 0; @@ -3845,18 +6987,69 @@ goto err; } - sensor_sd = get_remote_sensor(stream, &pad); + if (s->target == V4L2_SEL_TGT_CROP_BOUNDS) { + sensor_sd = get_remote_sensor(stream, &pad); - sd_sel.r = s->r; - sd_sel.pad = pad; - sd_sel.target = s->target; - sd_sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_sel.r = s->r; + sd_sel.pad = pad; + sd_sel.target = s->target; + sd_sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(sensor_sd, pad, set_selection, NULL, &sd_sel); - if (!ret) { - s->r = sd_sel.r; - v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "%s: pad:%d, which:%d, target:%d\n", - __func__, pad, sd_sel.which, sd_sel.target); + ret = v4l2_subdev_call(sensor_sd, pad, set_selection, NULL, &sd_sel); + if (!ret) { + s->r = sd_sel.r; + v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "%s: pad:%d, which:%d, target:%d\n", + __func__, pad, sd_sel.which, sd_sel.target); + } + } else if (s->target == V4L2_SEL_TGT_CROP) { + ret = rkcif_sanity_check_fmt(stream, rect); + if (ret) { + v4l2_err(&dev->v4l2_dev, "set crop failed\n"); + return ret; + } + + if (stream->crop_mask & CROP_SRC_SENSOR) { + sensor_crop = stream->crop[CROP_SRC_SENSOR]; + if (rect->left + rect->width > sensor_crop.width || + rect->top + rect->height > sensor_crop.height) { + v4l2_err(&dev->v4l2_dev, + "crop size is bigger than sensor input:left:%d, top:%d, width:%d, height:%d\n", + sensor_crop.left, sensor_crop.top, + sensor_crop.width, sensor_crop.height); + return -EINVAL; + } + } else { + if (rect->left + rect->width > raw_rect->width || + rect->top + rect->height > raw_rect->height) { + v4l2_err(&dev->v4l2_dev, + "crop size is bigger than sensor raw input:left:%d, top:%d, width:%d, height:%d\n", + raw_rect->left, raw_rect->top, + raw_rect->width, raw_rect->height); + return -EINVAL; + } + } + + stream->crop[CROP_SRC_USR] = *rect; + stream->crop_enable = true; + stream->crop_mask |= CROP_SRC_USR_MASK; + stream->crop[CROP_SRC_ACT] = stream->crop[CROP_SRC_USR]; + if (stream->crop_mask & CROP_SRC_SENSOR) { + sensor_crop = stream->crop[CROP_SRC_SENSOR]; + stream->crop[CROP_SRC_ACT].left = sensor_crop.left + stream->crop[CROP_SRC_USR].left; + stream->crop[CROP_SRC_ACT].top = sensor_crop.top + stream->crop[CROP_SRC_USR].top; + } + + if (stream->state == RKCIF_STATE_STREAMING) { + stream->crop_dyn_en = true; + + v4l2_info(&dev->v4l2_dev, "enable dynamic crop, S_SELECTION(%ux%u@%u:%u) target: %d\n", + rect->width, rect->height, rect->left, rect->top, s->target); + } else { + v4l2_info(&dev->v4l2_dev, "static crop, S_SELECTION(%ux%u@%u:%u) target: %d\n", + rect->width, rect->height, rect->left, rect->top, s->target); + } + } else { + goto err; } return ret; @@ -3866,7 +7059,7 @@ } static int rkcif_g_selection(struct file *file, void *fh, - struct v4l2_selection *s) + struct v4l2_selection *s) { struct rkcif_stream *stream = video_drvdata(file); struct rkcif_device *dev = stream->cifdev; @@ -3917,20 +7110,127 @@ return -EINVAL; } +static int rkcif_get_max_common_div(int a, int b) +{ + int remainder = a % b; + + while (remainder != 0) { + a = b; + b = remainder; + remainder = a % b; + } + return b; +} + +void rkcif_set_fps(struct rkcif_stream *stream, struct rkcif_fps *fps) +{ + struct rkcif_sensor_info *sensor = &stream->cifdev->terminal_sensor; + struct rkcif_device *cif_dev = stream->cifdev; + struct rkcif_stream *tmp_stream = NULL; + u32 numerator, denominator; + u32 def_fps = 0; + u32 cur_fps = 0; + int cap_m, skip_n; + int i = 0; + int max_common_div; + bool skip_en = false; + s32 vblank_def = 0; + s32 vblank_curr = 0; + int ret = 0; + + if (!stream->cifdev->terminal_sensor.sd) { + ret = rkcif_update_sensor_info(stream); + if (ret) { + v4l2_err(&stream->cifdev->v4l2_dev, + "%s update sensor info fail\n", + __func__); + return; + } + + } + if (!stream->cifdev->terminal_sensor.sd) + return; + numerator = sensor->fi.interval.numerator; + denominator = sensor->fi.interval.denominator; + def_fps = denominator / numerator; + + vblank_def = rkcif_get_sensor_vblank_def(cif_dev); + vblank_curr = rkcif_get_sensor_vblank(cif_dev); + if (vblank_def) + cur_fps = def_fps * (u32)(vblank_def + sensor->raw_rect.height) / + (u32)(vblank_curr + sensor->raw_rect.height); + else + cur_fps = def_fps; + + if (fps->fps == 0 || fps->fps > cur_fps) { + v4l2_err(&stream->cifdev->v4l2_dev, + "set fps %d fps failed, current fps %d fps\n", + fps->fps, cur_fps); + return; + } + cap_m = fps->fps; + skip_n = cur_fps - fps->fps; + max_common_div = rkcif_get_max_common_div(cap_m, skip_n); + cap_m /= max_common_div; + skip_n /= max_common_div; + if (cap_m > 64) { + skip_n = skip_n / (cap_m / 64); + if (skip_n == 0) + skip_n = 1; + cap_m = 64; + } + if (skip_n > 7) { + cap_m = cap_m / (skip_n / 7); + if (cap_m == 0) + cap_m = 1; + skip_n = 7; + } + + if (fps->fps == cur_fps) + skip_en = false; + else + skip_en = true; + + if (fps->ch_num > 1 && fps->ch_num < 4) { + for (i = 0; i < fps->ch_num; i++) { + tmp_stream = &cif_dev->stream[i]; + if (skip_en) { + tmp_stream->skip_info.skip_to_en = true; + tmp_stream->skip_info.cap_m = cap_m; + tmp_stream->skip_info.skip_n = skip_n; + } else { + tmp_stream->skip_info.skip_to_dis = true; + } + } + } else { + if (skip_en) { + stream->skip_info.skip_to_en = true; + stream->skip_info.cap_m = cap_m; + stream->skip_info.skip_n = skip_n; + } else { + stream->skip_info.skip_to_dis = true; + } + } + v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev, + "skip_to_en %d, cap_m %d, skip_n %d\n", + stream->skip_info.skip_to_en, + cap_m, + skip_n); +} + static int rkcif_do_reset_work(struct rkcif_device *cif_dev, enum rkmodule_reset_src reset_src); static long rkcif_ioctl_default(struct file *file, void *fh, - bool valid_prio, unsigned int cmd, void *arg) + bool valid_prio, unsigned int cmd, void *arg) { struct rkcif_stream *stream = video_drvdata(file); struct rkcif_device *dev = stream->cifdev; const struct cif_input_fmt *in_fmt; struct v4l2_rect rect; - int vc = 0; - struct rkcif_reset_info *reset_info; - int reset_src = 0; - unsigned long flags; + struct csi_channel_info csi_info; + struct rkcif_fps fps; + int reset_src; switch (cmd) { case RKCIF_CMD_GET_CSI_MEMORY_MODE: @@ -3945,7 +7245,8 @@ break; case RKCIF_CMD_SET_CSI_MEMORY_MODE: if (dev->terminal_sensor.sd) { - in_fmt = get_input_fmt(dev->terminal_sensor.sd, &rect, 0, &vc); + in_fmt = rkcif_get_input_fmt(dev, + &rect, 0, &csi_info); if (in_fmt == NULL) { v4l2_err(&dev->v4l2_dev, "can't get sensor input format\n"); return -EINVAL; @@ -3971,18 +7272,12 @@ stream->is_high_align = false; } break; - case RKCIF_CMD_GET_RESET_INFO: - reset_info = (struct rkcif_reset_info *)arg; - spin_lock_irqsave(&dev->hw_dev->spin_lock, flags); - *reset_info = dev->hw_dev->reset_info; - spin_unlock_irqrestore(&dev->hw_dev->spin_lock, flags); + case RKCIF_CMD_SET_FPS: + fps = *(struct rkcif_fps *)arg; + rkcif_set_fps(stream, &fps); break; case RKCIF_CMD_SET_RESET: reset_src = *(int *)arg; - spin_lock_irqsave(&dev->hw_dev->spin_lock, flags); - if (dev->hw_dev->reset_info.is_need_reset) - dev->hw_dev->reset_info.is_need_reset = 0; - spin_unlock_irqrestore(&dev->hw_dev->spin_lock, flags); return rkcif_do_reset_work(dev, reset_src); default: return -EINVAL; @@ -4003,13 +7298,10 @@ .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_enum_input = rkcif_enum_input, .vidioc_try_fmt_vid_cap_mplane = rkcif_try_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_cap_mplane = rkcif_enum_fmt_vid_cap_mplane, + .vidioc_enum_fmt_vid_cap = rkcif_enum_fmt_vid_cap_mplane, .vidioc_s_fmt_vid_cap_mplane = rkcif_s_fmt_vid_cap_mplane, .vidioc_g_fmt_vid_cap_mplane = rkcif_g_fmt_vid_cap_mplane, .vidioc_querycap = rkcif_querycap, - .vidioc_cropcap = rkcif_cropcap, - .vidioc_s_crop = rkcif_s_crop, - .vidioc_g_crop = rkcif_g_crop, .vidioc_s_selection = rkcif_s_selection, .vidioc_g_selection = rkcif_g_selection, .vidioc_enum_frameintervals = rkcif_enum_frameintervals, @@ -4017,8 +7309,59 @@ .vidioc_default = rkcif_ioctl_default, }; +void rkcif_vb_done_oneframe(struct rkcif_stream *stream, + struct vb2_v4l2_buffer *vb_done) +{ + const struct cif_output_fmt *fmt = stream->cif_fmt_out; + u32 i; + + /* Dequeue a filled buffer */ + for (i = 0; i < fmt->mplanes; i++) { + vb2_set_plane_payload(&vb_done->vb2_buf, i, + stream->pixm.plane_fmt[i].sizeimage); + } + + vb2_buffer_done(&vb_done->vb2_buf, VB2_BUF_STATE_DONE); + v4l2_dbg(2, rkcif_debug, &stream->cifdev->v4l2_dev, + "stream[%d] vb done, index: %d, sequence %d\n", stream->id, + vb_done->vb2_buf.index, vb_done->sequence); + atomic_dec(&stream->buf_cnt); +} + +static void rkcif_tasklet_handle(unsigned long data) +{ + struct rkcif_stream *stream = (struct rkcif_stream *)data; + struct rkcif_buffer *buf = NULL; + unsigned long flags = 0; + LIST_HEAD(local_list); + + spin_lock_irqsave(&stream->vbq_lock, flags); + list_replace_init(&stream->vb_done_list, &local_list); + spin_unlock_irqrestore(&stream->vbq_lock, flags); + + while (!list_empty(&local_list)) { + buf = list_first_entry(&local_list, + struct rkcif_buffer, queue); + list_del(&buf->queue); + rkcif_vb_done_oneframe(stream, &buf->vb); + } +} + +void rkcif_vb_done_tasklet(struct rkcif_stream *stream, struct rkcif_buffer *buf) +{ + unsigned long flags = 0; + + if (!stream || !buf) + return; + spin_lock_irqsave(&stream->vbq_lock, flags); + list_add_tail(&buf->queue, &stream->vb_done_list); + spin_unlock_irqrestore(&stream->vbq_lock, flags); + tasklet_schedule(&stream->vb_done_tasklet); +} + static void rkcif_unregister_stream_vdev(struct rkcif_stream *stream) { + tasklet_kill(&stream->vb_done_tasklet); media_entity_cleanup(&stream->vnode.vdev.entity); video_unregister_device(&stream->vnode.vdev); } @@ -4052,6 +7395,7 @@ vdev_name = CIF_DVP_VDEV_NAME; break; default: + ret = -EINVAL; v4l2_err(v4l2_dev, "Invalid stream\n"); goto unreg; } @@ -4074,6 +7418,7 @@ vdev_name = CIF_MIPI_ID3_VDEV_NAME; break; default: + ret = -EINVAL; v4l2_err(v4l2_dev, "Invalid stream\n"); goto unreg; } @@ -4092,6 +7437,7 @@ vdev_name = CIF_DVP_ID3_VDEV_NAME; break; default: + ret = -EINVAL; v4l2_err(v4l2_dev, "Invalid stream\n"); goto unreg; } @@ -4118,7 +7464,7 @@ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); vdev->queue = &node->buf_queue; - ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) { v4l2_err(v4l2_dev, "video_register_device failed with error %d\n", ret); @@ -4129,6 +7475,11 @@ if (ret < 0) goto unreg; + INIT_LIST_HEAD(&stream->vb_done_list); + tasklet_init(&stream->vb_done_tasklet, + rkcif_tasklet_handle, + (unsigned long)stream); + tasklet_disable(&stream->vb_done_tasklet); return 0; unreg: video_unregister_device(vdev); @@ -4161,7 +7512,7 @@ if (ret < 0) goto err; } - + dev->num_channels = stream_num; return 0; err: for (j = 0; j < i; j++) { @@ -4229,8 +7580,8 @@ } static struct v4l2_rect *rkcif_lvds_sd_get_crop(struct rkcif_lvds_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - enum v4l2_subdev_format_whence which) + struct v4l2_subdev_pad_config *cfg, + enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) return v4l2_subdev_get_try_crop(&subdev->sd, cfg, RKCIF_LVDS_PAD_SINK); @@ -4239,8 +7590,8 @@ } static int rkcif_lvds_sd_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) { struct rkcif_lvds_subdev *subdev = container_of(sd, struct rkcif_lvds_subdev, sd); struct v4l2_subdev *sensor = get_lvds_remote_sensor(sd); @@ -4255,8 +7606,8 @@ } static int rkcif_lvds_sd_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) { struct rkcif_lvds_subdev *subdev = container_of(sd, struct rkcif_lvds_subdev, sd); struct v4l2_subdev *sensor = get_lvds_remote_sensor(sd); @@ -4312,13 +7663,13 @@ return -EINVAL; } -static int rkcif_lvds_g_mbus_config(struct v4l2_subdev *sd, +static int rkcif_lvds_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, struct v4l2_mbus_config *mbus) { struct v4l2_subdev *sensor_sd = get_lvds_remote_sensor(sd); int ret; - ret = v4l2_subdev_call(sensor_sd, video, g_mbus_config, mbus); + ret = v4l2_subdev_call(sensor_sd, pad, get_mbus_config, 0, mbus); if (ret) return ret; @@ -4341,12 +7692,13 @@ } static int rkcif_sof_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) + struct v4l2_event_subscription *sub) { - if (sub->type != V4L2_EVENT_FRAME_SYNC) + if (sub->type == V4L2_EVENT_FRAME_SYNC || + sub->type == V4L2_EVENT_RESET_DEV) + return v4l2_event_subscribe(fh, sub, RKCIF_V4L2_EVENT_ELEMS, NULL); + else return -EINVAL; - - return v4l2_event_subscribe(fh, sub, 0, NULL); } static const struct media_entity_operations rkcif_lvds_sd_media_ops = { @@ -4359,10 +7711,10 @@ .get_fmt = rkcif_lvds_sd_get_fmt, .set_selection = rkcif_lvds_sd_set_selection, .get_selection = rkcif_lvds_sd_get_selection, + .get_mbus_config = rkcif_lvds_g_mbus_config, }; static const struct v4l2_subdev_video_ops rkcif_lvds_sd_video_ops = { - .g_mbus_config = rkcif_lvds_g_mbus_config, .s_stream = rkcif_lvds_sd_s_stream, }; @@ -4400,10 +7752,12 @@ return 0; } -static void rkcif_lvds_set_sof(struct rkcif_device *dev, u32 seq) +static u32 rkcif_lvds_set_sof(struct rkcif_device *dev, u32 seq) { if (dev) atomic_set(&dev->lvds_subdev.frm_sync_seq, seq); + + return 0; } int rkcif_register_lvds_subdev(struct rkcif_device *dev) @@ -4412,6 +7766,7 @@ struct rkcif_lvds_subdev *lvds_subdev = &dev->lvds_subdev; struct v4l2_subdev *sd; int ret; + int pad_num = 4; memset(lvds_subdev, 0, sizeof(*lvds_subdev)); lvds_subdev->cifdev = dev; @@ -4420,7 +7775,7 @@ v4l2_subdev_init(sd, &rkcif_lvds_sd_ops); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; sd->entity.ops = &rkcif_lvds_sd_media_ops; - if (dev->chip_id == CHIP_RV1126_CIF) + if (dev->chip_id != CHIP_RV1126_CIF_LITE) snprintf(sd->name, sizeof(sd->name), "rkcif-lvds-subdev"); else snprintf(sd->name, sizeof(sd->name), "rkcif-lite-lvds-subdev"); @@ -4431,6 +7786,13 @@ lvds_subdev->pads[RKCIF_LVDS_PAD_SRC_ID1].flags = MEDIA_PAD_FL_SOURCE; lvds_subdev->pads[RKCIF_LVDS_PAD_SRC_ID2].flags = MEDIA_PAD_FL_SOURCE; lvds_subdev->pads[RKCIF_LVDS_PAD_SRC_ID3].flags = MEDIA_PAD_FL_SOURCE; + if (dev->chip_id == CHIP_RV1106_CIF) { + lvds_subdev->pads[RKCIF_LVDS_PAD_SCL_ID0].flags = MEDIA_PAD_FL_SOURCE; + lvds_subdev->pads[RKCIF_LVDS_PAD_SCL_ID1].flags = MEDIA_PAD_FL_SOURCE; + lvds_subdev->pads[RKCIF_LVDS_PAD_SCL_ID2].flags = MEDIA_PAD_FL_SOURCE; + lvds_subdev->pads[RKCIF_LVDS_PAD_SCL_ID3].flags = MEDIA_PAD_FL_SOURCE; + pad_num = RKCIF_LVDS_PAD_MAX; + } lvds_subdev->in_fmt.width = RKCIF_DEFAULT_WIDTH; lvds_subdev->in_fmt.height = RKCIF_DEFAULT_HEIGHT; @@ -4439,7 +7801,7 @@ lvds_subdev->crop.width = RKCIF_DEFAULT_WIDTH; lvds_subdev->crop.height = RKCIF_DEFAULT_HEIGHT; - ret = media_entity_pads_init(&sd->entity, RKCIF_LVDS_PAD_MAX, + ret = media_entity_pads_init(&sd->entity, pad_num, lvds_subdev->pads); if (ret < 0) return ret; @@ -4491,10 +7853,12 @@ return 0; } -static void rkcif_dvp_set_sof(struct rkcif_device *dev, u32 seq) +static u32 rkcif_dvp_set_sof(struct rkcif_device *dev, u32 seq) { if (dev) atomic_set(&dev->dvp_sof_subdev.frm_sync_seq, seq); + + return 0; } static const struct v4l2_subdev_core_ops rkcif_dvp_sof_sd_core_ops = { @@ -4547,28 +7911,6 @@ v4l2_device_unregister_subdev(sd); } - -static void rkcif_vb_done_oneframe(struct rkcif_stream *stream, - struct vb2_v4l2_buffer *vb_done) -{ - const struct cif_output_fmt *fmt = stream->cif_fmt_out; - u32 i; - - /* Dequeue a filled buffer */ - for (i = 0; i < fmt->mplanes; i++) { - vb2_set_plane_payload(&vb_done->vb2_buf, i, - stream->pixm.plane_fmt[i].sizeimage); - } - - if (stream->cifdev->hdr.mode == NO_HDR) - vb_done->vb2_buf.timestamp = ktime_get_ns(); - - vb2_buffer_done(&vb_done->vb2_buf, VB2_BUF_STATE_DONE); - v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev, - "stream[%d] vb done, index: %d, sequence %d\n", stream->id, - vb_done->vb2_buf.index, vb_done->sequence); -} - void rkcif_irq_oneframe(struct rkcif_device *cif_dev) { /* TODO: xuhf-debug: add stream type */ @@ -4600,7 +7942,7 @@ } if ((intstat & FRAME_END)) { - struct vb2_v4l2_buffer *vb_done = NULL; + struct rkcif_buffer *active_buf = NULL; rkcif_write_register(cif_dev, CIF_REG_DVP_INTSTAT, FRAME_END_CLR); @@ -4633,11 +7975,11 @@ if (frmid % 2 != 0) { stream->frame_phase = CIF_CSI_FRAME0_READY; if (stream->curr_buf) - vb_done = &stream->curr_buf->vb; + active_buf = stream->curr_buf; } else { stream->frame_phase = CIF_CSI_FRAME1_READY; if (stream->next_buf) - vb_done = &stream->next_buf->vb; + active_buf = stream->next_buf; } /* In one-frame mode: @@ -4650,46 +7992,28 @@ ret = rkcif_assign_new_buffer_oneframe(stream, RKCIF_YUV_ADDR_STATE_UPDATE); - if (vb_done && (!ret)) { - vb_done->sequence = stream->frame_idx; - rkcif_vb_done_oneframe(stream, vb_done); + if (active_buf && (!ret)) { + active_buf->vb.sequence = stream->frame_idx - 1; + rkcif_vb_done_tasklet(stream, active_buf); } - stream->frame_idx++; - cif_dev->irq_stats.all_frm_end_cnt++; + cif_dev->irq_stats.frm_end_cnt[stream->id]++; } } static int rkcif_csi_g_mipi_id(struct v4l2_device *v4l2_dev, - unsigned int intstat) + unsigned int intstat) { - if (intstat & CSI_FRAME_END_ID0) { - if ((intstat & CSI_FRAME_END_ID0) == - CSI_FRAME_END_ID0) - v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in ID0\n"); + if (intstat & CSI_FRAME_END_ID0) return RKCIF_STREAM_MIPI_ID0; - } - if (intstat & CSI_FRAME_END_ID1) { - if ((intstat & CSI_FRAME_END_ID1) == - CSI_FRAME_END_ID1) - v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in ID1\n"); + if (intstat & CSI_FRAME_END_ID1) return RKCIF_STREAM_MIPI_ID1; - } - if (intstat & CSI_FRAME_END_ID2) { - if ((intstat & CSI_FRAME_END_ID2) == - CSI_FRAME_END_ID2) - v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in ID2\n"); + if (intstat & CSI_FRAME_END_ID2) return RKCIF_STREAM_MIPI_ID2; - } - - if (intstat & CSI_FRAME_END_ID3) { - if ((intstat & CSI_FRAME_END_ID3) == - CSI_FRAME_END_ID3) - v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in ID3\n"); + if (intstat & CSI_FRAME_END_ID3) return RKCIF_STREAM_MIPI_ID3; - } return -EINVAL; } @@ -4698,38 +8022,42 @@ u32 *intstat, u32 frm_stat) { if (*intstat & DVP_FRAME_END_ID0) { - if ((frm_stat & DVP_CHANNEL0_FRM_READ) == - DVP_CHANNEL0_FRM_READ) - v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in DVP ID0\n"); - *intstat &= ~DVP_FRAME_END_ID0; return RKCIF_STREAM_MIPI_ID0; } if (*intstat & DVP_FRAME_END_ID1) { - if ((frm_stat & DVP_CHANNEL1_FRM_READ) == - DVP_CHANNEL1_FRM_READ) - v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in DVP ID1\n"); - *intstat &= ~DVP_FRAME_END_ID1; return RKCIF_STREAM_MIPI_ID1; } if (*intstat & DVP_FRAME_END_ID2) { - if ((frm_stat & DVP_CHANNEL2_FRM_READ) == - DVP_CHANNEL2_FRM_READ) - v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in DVP ID2\n"); *intstat &= ~DVP_FRAME_END_ID2; return RKCIF_STREAM_MIPI_ID2; } if (*intstat & DVP_FRAME_END_ID3) { - if ((frm_stat & DVP_CHANNEL3_FRM_READ) == - DVP_CHANNEL3_FRM_READ) - v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in DVP ID3\n"); *intstat &= ~DVP_FRAME_END_ID3; return RKCIF_STREAM_MIPI_ID3; } + + return -EINVAL; +} + +static int rkcif_dvp_g_ch_id_by_fe(struct v4l2_device *v4l2_dev, + u32 intstat) +{ + if (intstat & DVP_ALL_END_ID0) + return RKCIF_STREAM_MIPI_ID0; + + if (intstat & DVP_ALL_END_ID1) + return RKCIF_STREAM_MIPI_ID1; + + if (intstat & DVP_ALL_END_ID2) + return RKCIF_STREAM_MIPI_ID2; + + if (intstat & DVP_ALL_END_ID3) + return RKCIF_STREAM_MIPI_ID3; return -EINVAL; } @@ -4740,7 +8068,6 @@ struct rkcif_device, reset_watchdog_timer); struct rkcif_stream *stream = &dev->stream[RKCIF_STREAM_MIPI_ID0]; - struct rkcif_hw_timer *hw_timer = &dev->hw_dev->hw_timer; bool is_triggered = false, is_assign_triggered = false, is_first_err = false; unsigned long flags; u64 cur_time, diff_time; @@ -4751,7 +8078,7 @@ timer->csi2_err_cnt_odd != 0) { timer->csi2_err_cnt_odd = 0; timer->csi2_err_cnt_even = 0; - hw_timer->reset_src = RKCIF_RESET_SRC_ERR_CSI2; + timer->reset_src = RKCIF_RESET_SRC_ERR_CSI2; timer->csi2_err_triggered_cnt++; if (timer->csi2_err_triggered_cnt == 1) { is_first_err = true; @@ -4770,7 +8097,7 @@ cur_time = ktime_get_ns(); diff_time = cur_time - timer->csi2_first_err_timestamp; diff_time = div_u64(diff_time, 1000000); - if (diff_time >= hw_timer->err_time_interval) { + if (diff_time >= timer->err_time_interval) { is_triggered = true; v4l2_info(&dev->v4l2_dev, "trigger reset for time out of csi err\n"); goto end_judge; @@ -4790,20 +8117,10 @@ * when fs cnt is beyond 2, it indicates that frame end is not coming, * or fs and fe had been not paired. */ - if (hw_timer->monitor_mode != RKCIF_MONITOR_MODE_HOTPLUG && - (stream->is_fs_fe_not_paired || - stream->fs_cnt_in_single_frame > RKCIF_FS_DETECTED_NUM)) { + if (stream->is_fs_fe_not_paired || + stream->fs_cnt_in_single_frame > RKCIF_FS_DETECTED_NUM) { is_triggered = true; v4l2_info(&dev->v4l2_dev, "reset for fs & fe not paired\n"); - } - if (dev->irq_stats.csi_bwidth_lack_cnt) { - is_triggered = true; - dev->irq_stats.csi_bwidth_lack_cnt = 0; - v4l2_info(&dev->v4l2_dev, "reset for bandwidth lack\n"); - } - if (dev->irq_stats.csi_overflow_cnt) { - is_triggered = true; - dev->irq_stats.csi_overflow_cnt = 0; } end_judge: spin_unlock_irqrestore(&timer->csi2_err_lock, flags); @@ -4811,7 +8128,30 @@ return is_triggered; } -static s32 rkcif_get_sensor_vblank(struct rkcif_device *dev) +static bool rkcif_is_triggered_monitoring(struct rkcif_device *dev) +{ + struct rkcif_timer *timer = &dev->reset_watchdog_timer; + struct rkcif_stream *stream = &dev->stream[RKCIF_STREAM_MIPI_ID0]; + bool ret = false; + + if (timer->monitor_mode == RKCIF_MONITOR_MODE_IDLE) + ret = false; + + if (timer->monitor_mode == RKCIF_MONITOR_MODE_CONTINUE || + timer->monitor_mode == RKCIF_MONITOR_MODE_HOTPLUG) { + if (stream->frame_idx >= timer->triggered_frame_num) + ret = true; + } + + if (timer->monitor_mode == RKCIF_MONITOR_MODE_TRIGGER) { + timer->is_csi2_err_occurred = rkcif_is_csi2_err_trigger_reset(timer); + ret = timer->is_csi2_err_occurred; + } + + return ret; +} + +s32 rkcif_get_sensor_vblank(struct rkcif_device *dev) { struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor; struct v4l2_subdev *sd = terminal_sensor->sd; @@ -4828,7 +8168,7 @@ return 0; } -static s32 rkcif_get_sensor_vblank_def(struct rkcif_device *dev) +s32 rkcif_get_sensor_vblank_def(struct rkcif_device *dev) { struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor; struct v4l2_subdev *sd = terminal_sensor->sd; @@ -4854,7 +8194,7 @@ const struct cif_output_fmt *fmt; u32 fourcc; - fmt = find_output_fmt(stream, stream->pixm.pixelformat); + fmt = rkcif_find_output_fmt(stream, stream->pixm.pixelformat); if (!fmt) { v4l2_err(&dev->v4l2_dev, "can not find output format: 0x%x", stream->pixm.pixelformat); @@ -4870,13 +8210,14 @@ * writing of ddr, aliged with 256 */ if (fmt->fmt_type == CIF_FMT_TYPE_RAW && stream->is_compact && - fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888) { + fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888 && + fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB565) { *crop_vwidth = ALIGN(raw_width * fmt->raw_bpp / 8, 256); } else { *crop_vwidth = ALIGN(raw_width * fmt->bpp[0] / 8, 8); } - if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888) + if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888 || channel->fmt_val == CSI_WRDDR_TYPE_RGB565) *crop_width = raw_width * fmt->bpp[0] / 8; /* * rk cif don't support output yuyv fmt data @@ -4904,12 +8245,15 @@ return; mbus = &cif_dev->active_sensor->mbus; - if (mbus->type == V4L2_MBUS_CSI2 || + if (mbus->type == V4L2_MBUS_CSI2_DPHY || + mbus->type == V4L2_MBUS_CSI2_CPHY || mbus->type == V4L2_MBUS_CCP2) { struct csi_channel_info *channel = &cif_dev->channels[stream->id]; if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888) crop_x = 3 * stream->crop[CROP_SRC_ACT].left; + else if (channel->fmt_val == CSI_WRDDR_TYPE_RGB565) + crop_x = 2 * stream->crop[CROP_SRC_ACT].left; else crop_x = stream->crop[CROP_SRC_ACT].left; @@ -4951,15 +8295,8 @@ crop_y << CIF_CROP_Y_SHIFT | crop_x); if (stream->cif_fmt_in->fmt_type == CIF_FMT_TYPE_RAW) { - fmt = find_output_fmt(stream, stream->pixm.pixelformat); - if (fmt->fourcc == V4L2_PIX_FMT_GREY || - fmt->fourcc == V4L2_PIX_FMT_SRGGB8 || - fmt->fourcc == V4L2_PIX_FMT_SGRBG8 || - fmt->fourcc == V4L2_PIX_FMT_SGBRG8 || - fmt->fourcc == V4L2_PIX_FMT_SBGGR8) - crop_vwidth = ALIGN(raw_width * fmt->raw_bpp / 8, 256); - else - crop_vwidth = raw_width * rkcif_cal_raw_vir_line_ratio(stream, fmt); + fmt = rkcif_find_output_fmt(stream, stream->pixm.pixelformat); + crop_vwidth = raw_width * rkcif_cal_raw_vir_line_ratio(stream, fmt); } rkcif_write_register(cif_dev, CIF_REG_DVP_VIR_LINE_WIDTH, crop_vwidth); @@ -4970,41 +8307,94 @@ stream->crop_dyn_en = false; } -void rkcif_monitor_reset_event(struct rkcif_hw *hw) +static void rkcif_monitor_reset_event(struct rkcif_device *dev) { - struct rkcif_hw_timer *hw_timer = &hw->hw_timer; - struct rkcif_timer *timer = NULL; - struct rkcif_device *cif_dev = NULL; struct rkcif_stream *stream = NULL; - unsigned long flags; - int i = 0, j = 0; + struct rkcif_timer *timer = &dev->reset_watchdog_timer; + unsigned int cycle = 0; + u64 fps, timestamp0, timestamp1; + unsigned long flags, fps_flags; + int i = 0; - if (hw_timer->is_running) + if (timer->is_running) return; - if (hw_timer->monitor_mode == RKCIF_MONITOR_MODE_IDLE) + if (timer->monitor_mode == RKCIF_MONITOR_MODE_IDLE) return; - spin_lock_irqsave(&hw_timer->timer_lock, flags); - hw_timer->is_running = true; - for (j = 0; i < hw->dev_num; j++) { - cif_dev = hw->cif_dev[i]; - timer = &cif_dev->reset_watchdog_timer; - for (i = 0; i < cif_dev->num_channels; i++) { - stream = &cif_dev->stream[i]; - if (stream->state == RKCIF_STATE_STREAMING) - timer->last_buf_wakeup_cnt[i] = stream->frame_idx; - } + for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { + stream = &dev->stream[i]; + if (stream->state == RKCIF_STATE_STREAMING) + break; } - hw_timer->cycle_jif = msecs_to_jiffies(hw_timer->monitor_cycle); - hw_timer->timer.expires = jiffies + hw_timer->cycle_jif; - mod_timer(&hw_timer->timer, hw_timer->timer.expires); - spin_unlock_irqrestore(&hw_timer->timer_lock, flags); + if (i >= RKCIF_MAX_STREAM_MIPI) + return; - v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, - "start monitor timer, monitor cycle %d\n", - hw_timer->monitor_cycle); + timer->is_triggered = rkcif_is_triggered_monitoring(dev); + + if (timer->is_triggered) { + struct v4l2_rect *raw_rect = &dev->terminal_sensor.raw_rect; + enum rkcif_monitor_mode mode; + s32 vblank = 0; + u32 vts = 0; + u64 numerator = 0; + u64 denominator = 0; + + if (stream->frame_idx > 2) { + spin_lock_irqsave(&stream->fps_lock, fps_flags); + timestamp0 = stream->fps_stats.frm0_timestamp; + timestamp1 = stream->fps_stats.frm1_timestamp; + spin_unlock_irqrestore(&stream->fps_lock, fps_flags); + + fps = timestamp0 > timestamp1 ? + timestamp0 - timestamp1 : timestamp1 - timestamp0; + fps = div_u64(fps, 1000); + } else { + numerator = dev->terminal_sensor.fi.interval.numerator; + denominator = dev->terminal_sensor.fi.interval.denominator; + fps = div_u64(1000000 * numerator, denominator); + } + spin_lock_irqsave(&timer->timer_lock, flags); + + timer->frame_end_cycle_us = fps; + + vblank = rkcif_get_sensor_vblank(dev); + timer->raw_height = raw_rect->height; + vts = timer->raw_height + vblank; + timer->vts = vts; + + timer->line_end_cycle = div_u64(timer->frame_end_cycle_us, timer->vts); + fps = div_u64(timer->frame_end_cycle_us, 1000); + cycle = fps * timer->frm_num_of_monitor_cycle; + timer->cycle = msecs_to_jiffies(cycle); + + timer->run_cnt = 0; + timer->is_running = true; + timer->is_buf_stop_update = false; + for (i = 0; i < dev->num_channels; i++) { + stream = &dev->stream[i]; + if (stream->state == RKCIF_STATE_STREAMING) + timer->last_buf_wakeup_cnt[i] = stream->buf_wake_up_cnt; + } + /* in trigger mode, monitoring count is fps */ + mode = timer->monitor_mode; + if (mode == RKCIF_MONITOR_MODE_CONTINUE || + mode == RKCIF_MONITOR_MODE_HOTPLUG) + timer->max_run_cnt = 0xffffffff - CIF_TIMEOUT_FRAME_NUM; + else + timer->max_run_cnt = div_u64(1000, fps) * 1; + + timer->timer.expires = jiffies + timer->cycle; + mod_timer(&timer->timer, timer->timer.expires); + + spin_unlock_irqrestore(&timer->timer_lock, flags); + + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, + "%s:mode:%d, raw height:%d,vblank:%d, cycle:%ld, fps:%llu\n", + __func__, timer->monitor_mode, raw_rect->height, + vblank, timer->cycle, div_u64(1000, fps)); + } } static void rkcif_rdbk_frame_end(struct rkcif_stream *stream) @@ -5014,13 +8404,15 @@ u32 denominator, numerator; u64 l_ts, m_ts, s_ts, time = 30000000LL; int ret, fps = -1; + int i = 0; + unsigned long flags; - if (dev->hdr.mode == HDR_X2) { + if (dev->hdr.hdr_mode == HDR_X2) { if (stream->id != RKCIF_STREAM_MIPI_ID1 || dev->stream[RKCIF_STREAM_MIPI_ID0].state != RKCIF_STATE_STREAMING || dev->stream[RKCIF_STREAM_MIPI_ID1].state != RKCIF_STATE_STREAMING) return; - } else if (dev->hdr.mode == HDR_X3) { + } else if (dev->hdr.hdr_mode == HDR_X3) { if (stream->id != RKCIF_STREAM_MIPI_ID2 || dev->stream[RKCIF_STREAM_MIPI_ID0].state != RKCIF_STATE_STREAMING || dev->stream[RKCIF_STREAM_MIPI_ID1].state != RKCIF_STATE_STREAMING || @@ -5033,13 +8425,13 @@ if (denominator && numerator) time = numerator * 1000 / denominator * 1000 * 1000; - if (dev->hdr.mode == HDR_X3) { + if (dev->hdr.hdr_mode == HDR_X3) { if (dev->rdbk_buf[RDBK_L] && dev->rdbk_buf[RDBK_M] && dev->rdbk_buf[RDBK_S]) { - l_ts = dev->rdbk_buf[RDBK_L]->vb.vb2_buf.timestamp; - m_ts = dev->rdbk_buf[RDBK_M]->vb.vb2_buf.timestamp; - s_ts = dev->rdbk_buf[RDBK_S]->vb.vb2_buf.timestamp; + l_ts = dev->rdbk_buf[RDBK_L]->fe_timestamp; + m_ts = dev->rdbk_buf[RDBK_M]->fe_timestamp; + s_ts = dev->rdbk_buf[RDBK_S]->fe_timestamp; if (m_ts < l_ts || s_ts < m_ts) { v4l2_err(&dev->v4l2_dev, @@ -5069,14 +8461,25 @@ goto RDBK_FRM_UNMATCH; } } - dev->rdbk_buf[RDBK_L]->vb.sequence = dev->rdbk_buf[RDBK_S]->vb.sequence; - dev->rdbk_buf[RDBK_M]->vb.sequence = dev->rdbk_buf[RDBK_S]->vb.sequence; - rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID0], - &dev->rdbk_buf[RDBK_L]->vb); - rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID1], - &dev->rdbk_buf[RDBK_M]->vb); - rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID2], - &dev->rdbk_buf[RDBK_S]->vb); + dev->rdbk_buf[RDBK_M]->vb.sequence = dev->rdbk_buf[RDBK_L]->vb.sequence; + dev->rdbk_buf[RDBK_S]->vb.sequence = dev->rdbk_buf[RDBK_L]->vb.sequence; + if (dev->is_support_tools && + dev->stream[RKCIF_STREAM_MIPI_ID0].tools_vdev->state == RKCIF_STATE_STREAMING && + dev->stream[RKCIF_STREAM_MIPI_ID1].tools_vdev->state == RKCIF_STATE_STREAMING && + dev->stream[RKCIF_STREAM_MIPI_ID2].tools_vdev->state == RKCIF_STATE_STREAMING) { + for (i = 0; i < 3; i++) { + spin_lock_irqsave(&dev->stream[i].tools_vdev->vbq_lock, flags); + list_add_tail(&dev->rdbk_buf[i]->queue, + &dev->stream[i].tools_vdev->buf_done_head); + if (!work_busy(&dev->stream[i].tools_vdev->work)) + schedule_work(&dev->stream[i].tools_vdev->work); + spin_unlock_irqrestore(&dev->stream[i].tools_vdev->vbq_lock, flags); + } + } else { + rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID0], dev->rdbk_buf[RDBK_L]); + rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID1], dev->rdbk_buf[RDBK_M]); + rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID2], dev->rdbk_buf[RDBK_S]); + } } else { if (!dev->rdbk_buf[RDBK_L]) v4l2_err(&dev->v4l2_dev, "lost long frames\n"); @@ -5086,10 +8489,10 @@ v4l2_err(&dev->v4l2_dev, "lost short frames\n"); goto RDBK_FRM_UNMATCH; } - } else if (dev->hdr.mode == HDR_X2) { + } else if (dev->hdr.hdr_mode == HDR_X2) { if (dev->rdbk_buf[RDBK_L] && dev->rdbk_buf[RDBK_M]) { - l_ts = dev->rdbk_buf[RDBK_L]->vb.vb2_buf.timestamp; - s_ts = dev->rdbk_buf[RDBK_M]->vb.vb2_buf.timestamp; + l_ts = dev->rdbk_buf[RDBK_L]->fe_timestamp; + s_ts = dev->rdbk_buf[RDBK_M]->fe_timestamp; if (s_ts < l_ts) { v4l2_err(&dev->v4l2_dev, @@ -5118,11 +8521,22 @@ goto RDBK_FRM_UNMATCH; } } - dev->rdbk_buf[RDBK_L]->vb.sequence = dev->rdbk_buf[RDBK_M]->vb.sequence; - rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID0], - &dev->rdbk_buf[RDBK_L]->vb); - rkcif_vb_done_oneframe(&dev->stream[RKCIF_STREAM_MIPI_ID1], - &dev->rdbk_buf[RDBK_M]->vb); + dev->rdbk_buf[RDBK_M]->vb.sequence = dev->rdbk_buf[RDBK_L]->vb.sequence; + if (dev->is_support_tools && + dev->stream[RKCIF_STREAM_MIPI_ID0].tools_vdev->state == RKCIF_STATE_STREAMING && + dev->stream[RKCIF_STREAM_MIPI_ID1].tools_vdev->state == RKCIF_STATE_STREAMING) { + for (i = 0; i < 2; i++) { + spin_lock_irqsave(&dev->stream[i].tools_vdev->vbq_lock, flags); + list_add_tail(&dev->rdbk_buf[i]->queue, + &dev->stream[i].tools_vdev->buf_done_head); + if (!work_busy(&dev->stream[i].tools_vdev->work)) + schedule_work(&dev->stream[i].tools_vdev->work); + spin_unlock_irqrestore(&dev->stream[i].tools_vdev->vbq_lock, flags); + } + } else { + rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID0], dev->rdbk_buf[RDBK_L]); + rkcif_vb_done_tasklet(&dev->stream[RKCIF_STREAM_MIPI_ID1], dev->rdbk_buf[RDBK_M]); + } } else { if (!dev->rdbk_buf[RDBK_L]) v4l2_err(&dev->v4l2_dev, "lost long frames\n"); @@ -5130,8 +8544,6 @@ v4l2_err(&dev->v4l2_dev, "lost short frames\n"); goto RDBK_FRM_UNMATCH; } - } else { - rkcif_vb_done_oneframe(stream, &dev->rdbk_buf[RDBK_S]->vb); } dev->rdbk_buf[RDBK_L] = NULL; @@ -5158,10 +8570,26 @@ dev->rdbk_buf[RDBK_S] = NULL; } +static void rkcif_buf_done_with_tools(struct rkcif_stream *stream, + struct rkcif_buffer *active_buf) +{ + unsigned long flags; + + spin_lock_irqsave(&stream->tools_vdev->vbq_lock, flags); + if (stream->tools_vdev->state == RKCIF_STATE_STREAMING) { + list_add_tail(&active_buf->queue, &stream->tools_vdev->buf_done_head); + if (!work_busy(&stream->tools_vdev->work)) + schedule_work(&stream->tools_vdev->work); + } else { + rkcif_vb_done_tasklet(stream, active_buf); + } + spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags); +} + static void rkcif_buf_done_prepare(struct rkcif_stream *stream, - struct rkcif_buffer *active_buf, - int mipi_id, - u32 mode) + struct rkcif_buffer *active_buf, + int mipi_id, + u32 mode) { unsigned long flags; struct vb2_v4l2_buffer *vb_done = NULL; @@ -5169,8 +8597,13 @@ if (active_buf) { vb_done = &active_buf->vb; - vb_done->vb2_buf.timestamp = ktime_get_ns(); - vb_done->sequence = stream->frame_idx; + if (cif_dev->chip_id < CHIP_RK3588_CIF && + cif_dev->active_sensor->mbus.type == V4L2_MBUS_BT656) + vb_done->vb2_buf.timestamp = stream->readout.fe_timestamp; + else + vb_done->vb2_buf.timestamp = stream->readout.fs_timestamp; + vb_done->sequence = stream->frame_idx - 1; + active_buf->fe_timestamp = ktime_get_ns(); if (stream->is_line_wake_up) { spin_lock_irqsave(&stream->fps_lock, flags); if (mode) @@ -5184,13 +8617,22 @@ vb_done->sequence /= 2; } - if (cif_dev->hdr.mode == NO_HDR) { + if (cif_dev->hdr.hdr_mode == NO_HDR || cif_dev->hdr.hdr_mode == HDR_COMPR) { if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { - if (stream->frame_phase == CIF_CSI_FRAME1_READY && active_buf) - rkcif_vb_done_oneframe(stream, vb_done); + if (stream->frame_phase == CIF_CSI_FRAME1_READY && active_buf) { + + if (cif_dev->is_support_tools && stream->tools_vdev) + rkcif_buf_done_with_tools(stream, active_buf); + else + rkcif_vb_done_tasklet(stream, active_buf); + } } else { - if (active_buf) - rkcif_vb_done_oneframe(stream, vb_done); + if (active_buf) { + if (cif_dev->is_support_tools && stream->tools_vdev) + rkcif_buf_done_with_tools(stream, active_buf); + else + rkcif_vb_done_tasklet(stream, active_buf); + } } } else { if (cif_dev->is_start_hdr) { @@ -5199,11 +8641,12 @@ if (cif_dev->rdbk_buf[RDBK_L]) { v4l2_err(&cif_dev->v4l2_dev, "multiple long data in %s frame,frm_idx:%d,state:0x%x\n", - cif_dev->hdr.mode == HDR_X2 ? "hdr_x2" : "hdr_x3", + cif_dev->hdr.hdr_mode == HDR_X2 ? "hdr_x2" : "hdr_x3", stream->frame_idx, cif_dev->rdbk_buf[RDBK_L]->vb.vb2_buf.state); cif_dev->rdbk_buf[RDBK_L]->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; rkcif_buf_queue(&cif_dev->rdbk_buf[RDBK_L]->vb.vb2_buf); + cif_dev->rdbk_buf[RDBK_L] = NULL; } if (active_buf) cif_dev->rdbk_buf[RDBK_L] = active_buf; @@ -5211,29 +8654,31 @@ if (cif_dev->rdbk_buf[RDBK_M]) { v4l2_err(&cif_dev->v4l2_dev, "multiple %s frame,frm_idx:%d,state:0x%x\n", - cif_dev->hdr.mode == HDR_X2 ? "short data in hdr_x2" : "medium data in hdr_x3", + cif_dev->hdr.hdr_mode == HDR_X2 ? "short data in hdr_x2" : "medium data in hdr_x3", stream->frame_idx, cif_dev->rdbk_buf[RDBK_M]->vb.vb2_buf.state); cif_dev->rdbk_buf[RDBK_M]->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; rkcif_buf_queue(&cif_dev->rdbk_buf[RDBK_M]->vb.vb2_buf); + cif_dev->rdbk_buf[RDBK_M] = NULL; } if (active_buf) cif_dev->rdbk_buf[RDBK_M] = active_buf; - if (cif_dev->hdr.mode == HDR_X2) + if (cif_dev->hdr.hdr_mode == HDR_X2) rkcif_rdbk_frame_end(stream); } else if (mipi_id == RKCIF_STREAM_MIPI_ID2) { if (cif_dev->rdbk_buf[RDBK_S]) { v4l2_err(&cif_dev->v4l2_dev, "multiple %s frame, frm_idx:%d,state:0x%x\n", - cif_dev->hdr.mode == HDR_X2 ? "err short data in hdr_x3" : "short data in hdr_x3", + cif_dev->hdr.hdr_mode == HDR_X2 ? "err short data in hdr_x3" : "short data in hdr_x3", stream->frame_idx, cif_dev->rdbk_buf[RDBK_S]->vb.vb2_buf.state); cif_dev->rdbk_buf[RDBK_S]->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; rkcif_buf_queue(&cif_dev->rdbk_buf[RDBK_S]->vb.vb2_buf); + cif_dev->rdbk_buf[RDBK_S] = NULL; } if (active_buf) cif_dev->rdbk_buf[RDBK_S] = active_buf; - if (cif_dev->hdr.mode == HDR_X3) + if (cif_dev->hdr.hdr_mode == HDR_X3) rkcif_rdbk_frame_end(stream); } spin_unlock_irqrestore(&cif_dev->hdr_lock, flags); @@ -5276,12 +8721,129 @@ } ret = rkcif_get_new_buffer_wake_up_mode(stream); if (ret) - goto end_wake_up; - + return; rkcif_buf_done_prepare(stream, active_buf, mipi_id, mode); -end_wake_up: - stream->frame_idx++; +} +static void rkcif_store_last_buf_for_online(struct rkcif_stream *stream, + struct rkcif_rx_buffer *buf) +{ + struct rkcif_device *dev = stream->cifdev; + struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + u32 frm0_addr_y, frm1_addr_y; + + INIT_LIST_HEAD(&stream->rx_buf_head); + stream->curr_buf_toisp = buf; + stream->next_buf_toisp = buf; + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm0_addr_y = get_reg_index_of_frm0_y_addr(stream->id); + frm1_addr_y = get_reg_index_of_frm1_y_addr(stream->id); + } else { + frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(stream->id); + frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(stream->id); + } + rkcif_write_register(dev, frm0_addr_y, + buf->dummy.dma_addr); + rkcif_write_register(dev, frm1_addr_y, + buf->dummy.dma_addr); +} + +static void rkcif_release_unnecessary_buf_for_online(struct rkcif_stream *stream, + struct rkcif_rx_buffer *buf) +{ + struct rkcif_device *dev = stream->cifdev; + struct sditf_priv *priv = dev->sditf[0]; + struct rkcif_rx_buffer *rx_buf = NULL; + unsigned long flags; + int i = 0; + + spin_lock_irqsave(&priv->cif_dev->buffree_lock, flags); + for (i = 0; i < priv->buf_num; i++) { + rx_buf = &stream->rx_buf[i]; + if (rx_buf && (!rx_buf->dummy.is_free) && rx_buf != buf) { + list_add_tail(&rx_buf->list_free, &priv->buf_free_list); + stream->total_buf_num--; + } + } + spin_unlock_irqrestore(&priv->cif_dev->buffree_lock, flags); + schedule_work(&priv->buffree_work.work); +} + +static void rkcif_line_wake_up_rdbk(struct rkcif_stream *stream, int mipi_id) +{ + u32 mode; + struct rkcif_rx_buffer *active_buf = NULL; + struct sditf_priv *priv = NULL; + unsigned long flags; + int ret = 0; + + mode = stream->line_int_cnt % 2; + if (mode) { + if (stream->curr_buf_toisp) + active_buf = stream->curr_buf_toisp; + stream->frame_phase = CIF_CSI_FRAME0_READY; + } else { + if (stream->next_buf_toisp) + active_buf = stream->next_buf_toisp; + stream->frame_phase = CIF_CSI_FRAME1_READY; + } + + if (!active_buf) { + v4l2_err(&stream->cifdev->v4l2_dev, + "err buffer state in %s\n", + __func__); + return; + } + + if (stream->stopping) { + stream->is_can_stop = true; + return; + } + ret = rkcif_get_new_buffer_wake_up_mode_rdbk(stream); + v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev, + "%d frame_idx %d, last_rx_buf_idx %d cur dma buf %x\n", + __LINE__, stream->frame_idx, stream->last_rx_buf_idx, + (u32)active_buf->dummy.dma_addr); + if (!ret) { + priv = stream->cifdev->sditf[0]; + if (stream->cur_stream_mode & RKCIF_STREAM_MODE_TOISP_RDBK) { + spin_lock_irqsave(&stream->vbq_lock, flags); + if (stream->cifdev->is_thunderboot && + (stream->frame_idx - 1) == stream->last_rx_buf_idx && + stream->cifdev->is_rdbk_to_online) { + stream->cur_stream_mode &= ~RKCIF_STREAM_MODE_TOISP_RDBK; + stream->cur_stream_mode |= RKCIF_STREAM_MODE_TOISP; + stream->cifdev->wait_line = 0; + stream->is_line_wake_up = false; + if (stream->cifdev->hdr.hdr_mode == NO_HDR || + (priv->hdr_cfg.hdr_mode == HDR_X2 && stream->id == 1) || + (priv->hdr_cfg.hdr_mode == HDR_X3 && stream->id == 2)) { + stream->to_stop_dma = RKCIF_DMAEN_BY_ISP; + rkcif_stop_dma_capture(stream); + } + active_buf->dbufs.is_switch = true; + if ((priv->hdr_cfg.hdr_mode == HDR_X2 && stream->id != 1) || + (priv->hdr_cfg.hdr_mode == HDR_X3 && stream->id != 2)) { + rkcif_store_last_buf_for_online(stream, active_buf); + stream->is_change_toisp = true; + } + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); + active_buf->dbufs.sequence = stream->frame_idx - 1; + active_buf->dbufs.timestamp = stream->readout.fs_timestamp; + active_buf->fe_timestamp = ktime_get_ns(); + stream->last_frame_idx = stream->frame_idx; + if (stream->cifdev->hdr.hdr_mode == NO_HDR) { + rkcif_s_rx_buffer(stream->cifdev, &active_buf->dbufs); + if (stream->cifdev->is_support_tools && stream->tools_vdev) + rkcif_rdbk_with_tools(stream, active_buf); + } else { + rkcif_rdbk_frame_end_toisp(stream, active_buf); + } + } + } } static void rkcif_deal_readout_time(struct rkcif_stream *stream) @@ -5292,17 +8854,24 @@ spin_lock_irqsave(&stream->fps_lock, flags); stream->readout.fe_timestamp = ktime_get_ns(); + + if (cif_dev->inf_id == RKCIF_DVP) { + spin_unlock_irqrestore(&stream->fps_lock, flags); + return; + } + if (stream->id == RKCIF_STREAM_MIPI_ID0) detect_stream->readout.readout_time = stream->readout.fe_timestamp - stream->readout.fs_timestamp; - if ((cif_dev->hdr.mode == NO_HDR) && (stream->id == RKCIF_STREAM_MIPI_ID0)) { + if ((cif_dev->hdr.hdr_mode == NO_HDR || cif_dev->hdr.hdr_mode == HDR_COMPR) && + (stream->id == RKCIF_STREAM_MIPI_ID0)) { detect_stream->readout.early_time = stream->readout.fe_timestamp - stream->readout.wk_timestamp; - } else if ((cif_dev->hdr.mode == HDR_X2) && (stream->id == RKCIF_STREAM_MIPI_ID1)) { + } else if ((cif_dev->hdr.hdr_mode == HDR_X2) && (stream->id == RKCIF_STREAM_MIPI_ID1)) { detect_stream->readout.early_time = stream->readout.fe_timestamp - stream->readout.wk_timestamp; detect_stream->readout.total_time = stream->readout.fe_timestamp - detect_stream->readout.fe_timestamp; detect_stream->readout.total_time += detect_stream->readout.readout_time; - } else if ((cif_dev->hdr.mode == HDR_X3) && (stream->id == RKCIF_STREAM_MIPI_ID2)) { + } else if ((cif_dev->hdr.hdr_mode == HDR_X3) && (stream->id == RKCIF_STREAM_MIPI_ID2)) { detect_stream->readout.early_time = stream->readout.fe_timestamp - stream->readout.wk_timestamp; detect_stream->readout.total_time = stream->readout.fe_timestamp - detect_stream->readout.fe_timestamp; detect_stream->readout.total_time += detect_stream->readout.readout_time; @@ -5321,11 +8890,8 @@ int ret = 0; if (stream->frame_phase == (CIF_CSI_FRAME0_READY | CIF_CSI_FRAME1_READY)) { - - v4l2_err(&cif_dev->v4l2_dev, "stream[%d], frm0/frm1 end simultaneously,frm id:%d\n", - stream->id, stream->frame_idx); - - stream->frame_idx++; + cif_dev->err_state |= (RKCIF_ERR_ID0_TRIG_SIMULT << stream->id); + cif_dev->irq_stats.trig_simult_cnt[stream->id]++; return; } if (!stream->is_line_wake_up) { @@ -5343,89 +8909,174 @@ spin_unlock_irqrestore(&stream->fps_lock, flags); } - if (cif_dev->inf_id == RKCIF_MIPI_LVDS) - rkcif_deal_readout_time(stream); + rkcif_deal_readout_time(stream); + + if (!stream->is_line_wake_up) { + ret = rkcif_assign_new_buffer_pingpong(stream, + RKCIF_YUV_ADDR_STATE_UPDATE, + mipi_id); + if (ret && cif_dev->chip_id < CHIP_RK3588_CIF) + return; + } else { + ret = rkcif_update_new_buffer_wake_up_mode(stream); + if (ret && cif_dev->chip_id < CHIP_RK3588_CIF) + return; + } + if (cif_dev->chip_id < CHIP_RK3588_CIF && + cif_dev->active_sensor->mbus.type == V4L2_MBUS_BT656 && + stream->id != 0) + stream->frame_idx++; + if (!stream->is_line_wake_up && stream->dma_en & RKCIF_DMAEN_BY_VICAP) + rkcif_buf_done_prepare(stream, active_buf, mipi_id, 0); if (cif_dev->chip_id == CHIP_RV1126_CIF || cif_dev->chip_id == CHIP_RV1126_CIF_LITE || cif_dev->chip_id == CHIP_RK3568_CIF) - rkcif_luma_isr(&cif_dev->luma_vdev, mipi_id, stream->frame_idx); - - if (!stream->is_line_wake_up) { - ret = rkcif_assign_new_buffer_pingpong(stream, - RKCIF_YUV_ADDR_STATE_UPDATE, - mipi_id); - if (ret) - goto end; - } else { - ret = rkcif_update_new_buffer_wake_up_mode(stream); - if (ret) - return; - } - if (!stream->is_line_wake_up) - rkcif_buf_done_prepare(stream, active_buf, mipi_id, 0); - -end: - if (!stream->is_line_wake_up) - stream->frame_idx++; + rkcif_luma_isr(&cif_dev->luma_vdev, mipi_id, cif_dev->stream[0].frame_idx - 1); } -u32 rkcif_get_sof(struct rkcif_device *cif_dev) +static void rkcif_update_stream_toisp(struct rkcif_device *cif_dev, + struct rkcif_stream *stream, + int mipi_id) +{ + if (stream->frame_phase == (CIF_CSI_FRAME0_READY | CIF_CSI_FRAME1_READY)) { + + v4l2_err(&cif_dev->v4l2_dev, "stream[%d], frm0/frm1 end simultaneously,frm id:%d\n", + stream->id, stream->frame_idx); + return; + } + + spin_lock(&stream->fps_lock); + if (stream->frame_phase & CIF_CSI_FRAME0_READY) + stream->fps_stats.frm0_timestamp = ktime_get_ns(); + else if (stream->frame_phase & CIF_CSI_FRAME1_READY) + stream->fps_stats.frm1_timestamp = ktime_get_ns(); + spin_unlock(&stream->fps_lock); + + if (cif_dev->inf_id == RKCIF_MIPI_LVDS) + rkcif_deal_readout_time(stream); + + if (!stream->is_line_wake_up) + rkcif_assign_new_buffer_pingpong_toisp(stream, + RKCIF_YUV_ADDR_STATE_UPDATE, + mipi_id); +} + +static void rkcif_update_stream_rockit(struct rkcif_device *cif_dev, + struct rkcif_stream *stream, + int mipi_id) +{ + struct rkcif_buffer *active_buf = NULL; + unsigned long flags; + int ret = 0; + + if (stream->frame_phase == (CIF_CSI_FRAME0_READY | CIF_CSI_FRAME1_READY)) { + + v4l2_err(&cif_dev->v4l2_dev, "stream[%d], frm0/frm1 end simultaneously,frm id:%d\n", + stream->id, stream->frame_idx); + return; + } + if (!stream->is_line_wake_up) { + + spin_lock_irqsave(&stream->fps_lock, flags); + if (stream->frame_phase & CIF_CSI_FRAME0_READY) { + if (stream->curr_buf_rockit) + active_buf = stream->curr_buf_rockit; + stream->fps_stats.frm0_timestamp = ktime_get_ns(); + } else if (stream->frame_phase & CIF_CSI_FRAME1_READY) { + if (stream->next_buf_rockit) + active_buf = stream->next_buf_rockit; + stream->fps_stats.frm1_timestamp = ktime_get_ns(); + } + spin_unlock_irqrestore(&stream->fps_lock, flags); + } + + if (cif_dev->inf_id == RKCIF_MIPI_LVDS) + rkcif_deal_readout_time(stream); + + ret = rkcif_assign_new_buffer_pingpong_rockit(stream, + RKCIF_YUV_ADDR_STATE_UPDATE, + mipi_id); + if (ret) + return; + + if (active_buf) { + active_buf->vb.vb2_buf.timestamp = stream->readout.fs_timestamp; + active_buf->vb.sequence = stream->frame_idx - 1; + rkcif_rockit_buf_done(stream, active_buf); + } +} + +static u32 rkcif_get_sof(struct rkcif_device *cif_dev) { u32 val = 0x0; struct rkcif_sensor_info *sensor = cif_dev->active_sensor; + struct csi2_dev *csi; - if (sensor->mbus.type == V4L2_MBUS_CSI2) - val = rkcif_csi2_get_sof(); - else if (sensor->mbus.type == V4L2_MBUS_CCP2) + if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + sensor->mbus.type == V4L2_MBUS_CSI2_CPHY) { + csi = container_of(sensor->sd, struct csi2_dev, sd); + val = rkcif_csi2_get_sof(csi); + } else if (sensor->mbus.type == V4L2_MBUS_CCP2) { val = rkcif_lvds_get_sof(cif_dev); - else if (sensor->mbus.type == V4L2_MBUS_PARALLEL || - sensor->mbus.type == V4L2_MBUS_BT656) + } else if (sensor->mbus.type == V4L2_MBUS_PARALLEL || + sensor->mbus.type == V4L2_MBUS_BT656) { val = rkcif_dvp_get_sof(cif_dev); - + } return val; } static void rkcif_set_sof(struct rkcif_device *cif_dev, u32 seq) { struct rkcif_sensor_info *sensor = cif_dev->active_sensor; + struct csi2_dev *csi; - if (sensor->mbus.type == V4L2_MBUS_CSI2) - rkcif_csi2_set_sof(seq); - else if (sensor->mbus.type == V4L2_MBUS_CCP2) + if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + sensor->mbus.type == V4L2_MBUS_CSI2_CPHY) { + csi = container_of(sensor->sd, struct csi2_dev, sd); + rkcif_csi2_set_sof(csi, seq); + } else if (sensor->mbus.type == V4L2_MBUS_CCP2) { rkcif_lvds_set_sof(cif_dev, seq); - else if (sensor->mbus.type == V4L2_MBUS_PARALLEL || - sensor->mbus.type == V4L2_MBUS_BT656) + } else if (sensor->mbus.type == V4L2_MBUS_PARALLEL || + sensor->mbus.type == V4L2_MBUS_BT656) { rkcif_dvp_set_sof(cif_dev, seq); + } } -static int rkcif_streamoff_in_reset(struct rkcif_device *cif_dev, - struct rkcif_stream *resume_stream[], - struct rkcif_resume_info *resume_info, - enum rkmodule_reset_src reset_src) +static int rkcif_do_reset_work(struct rkcif_device *cif_dev, + enum rkmodule_reset_src reset_src) { - struct rkcif_stream *stream = NULL; struct rkcif_pipeline *p = &cif_dev->pipe; + struct rkcif_stream *stream = NULL; + struct rkcif_stream *resume_stream[RKCIF_MAX_STREAM_MIPI] = { NULL }; struct rkcif_sensor_info *terminal_sensor = &cif_dev->terminal_sensor; - u32 on, sof_cnt; + struct rkcif_resume_info *resume_info = &cif_dev->reset_work.resume_info; + struct rkcif_timer *timer = &cif_dev->reset_watchdog_timer; + struct sditf_priv *priv = cif_dev->sditf[0]; int i, j, ret = 0; - int stream_off_cnt = 0; + u32 on, sof_cnt; + int capture_mode = 0; + + mutex_lock(&cif_dev->stream_lock); + if (cif_dev->reset_work_cancel) { + ret = 0; + goto unlock_stream; + } + v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, "do rkcif reset\n"); for (i = 0, j = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { stream = &cif_dev->stream[i]; + if (stream->state == RKCIF_STATE_STREAMING) { - stream_off_cnt++; v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, "stream[%d] stopping\n", stream->id); rkcif_stream_stop(stream); - atomic_dec(&p->stream_cnt); - if (stream->id == RKCIF_STREAM_MIPI_ID0) { sof_cnt = rkcif_get_sof(cif_dev); - v4l2_err(&cif_dev->v4l2_dev, + v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, "%s: stream[%d] sync frmid & csi_sof, frm_id:%d, csi_sof:%d\n", __func__, stream->id, @@ -5443,57 +9094,63 @@ v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, "%s stop stream[%d] in streaming, frm_id:%d, csi_sof:%d\n", - __func__, stream->id, stream->frame_idx, rkcif_csi2_get_sof()); + __func__, stream->id, stream->frame_idx, rkcif_get_sof(cif_dev)); } } - if (!stream_off_cnt) - return 0; on = 0; for (i = 0; i < p->num_subdevs; i++) { if (p->subdevs[i] == terminal_sensor->sd) { - if (reset_src == RKCIF_RESET_SRC_ERR_CSI2 || - reset_src == RKCIF_RESET_SRC_ERR_HOTPLUG || - reset_src == RKICF_RESET_SRC_ERR_CUTOFF) { - + if (reset_src != RKCIF_RESET_SRC_ERR_APP) { ret = v4l2_subdev_call(p->subdevs[i], core, ioctl, RKMODULE_SET_QUICK_STREAM, &on); if (ret) - v4l2_err(&cif_dev->v4l2_dev, "quick stream off subdev:%s failed\n", + v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, + "quick stream off subdev:%s failed\n", p->subdevs[i]->name); } + } else { + ret = v4l2_subdev_call(p->subdevs[i], video, s_stream, on); } - if (ret) - v4l2_err(&cif_dev->v4l2_dev, "%s:stream %s subdev:%s failed\n", + v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, + "%s:stream %s subdev:%s failed\n", __func__, on ? "on" : "off", p->subdevs[i]->name); - } - return ret; -} -static int rkcif_streamon_in_reset(struct rkcif_device *cif_dev, - struct rkcif_stream *resume_stream[], - struct rkcif_resume_info *resume_info, - enum rkmodule_reset_src reset_src) -{ - struct rkcif_timer *timer = &cif_dev->reset_watchdog_timer; - struct rkcif_stream *stream = NULL; - struct rkcif_pipeline *p = &cif_dev->pipe; - struct rkcif_sensor_info *terminal_sensor = &cif_dev->terminal_sensor; - int i = 0; - int ret = 0; - int on = 0; - int stream_on_cnt = 0; + if (priv && priv->is_combine_mode && cif_dev->sditf_cnt <= RKCIF_MAX_SDITF) { + for (i = 0; i < cif_dev->sditf_cnt; i++) { + if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd) + ret = v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, ioctl, + RKMODULE_SET_QUICK_STREAM, &on); + } + } - for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { + rockchip_clear_system_status(SYS_STATUS_CIF0); + + if (cif_dev->chip_id >= CHIP_RK3588_CIF) { + rkcif_do_soft_reset(cif_dev); + } else { + + rkcif_do_cru_reset(cif_dev); + + rkcif_disable_sys_clk(cif_dev->hw_dev); + + udelay(5); + + ret = rkcif_enable_sys_clk(cif_dev->hw_dev); + + if (ret < 0) { + v4l2_err(&cif_dev->v4l2_dev, "%s:resume cif clk failed\n", __func__); + goto unlock_stream; + } + } + + for (i = 0; i < j; i++) { stream = resume_stream[i]; - if (stream == NULL || stream->state != RKCIF_STATE_RESET_IN_STREAMING) - break; - stream_on_cnt++; stream->fs_cnt_in_single_frame = 0; if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { if (stream->curr_buf == stream->next_buf) { @@ -5508,25 +9165,35 @@ stream->curr_buf = NULL; stream->next_buf = NULL; } - if (cif_dev->active_sensor->mbus.type == V4L2_MBUS_CSI2 || - cif_dev->active_sensor->mbus.type == V4L2_MBUS_CCP2) - ret = rkcif_csi_stream_start(stream); + if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode == RKISP_VICAP_RDBK_AIQ) + capture_mode = RKCIF_STREAM_MODE_CAPTURE; + else { + if (cif_dev->sditf[0]->mode.rdbk_mode == RKISP_VICAP_ONLINE) + capture_mode = RKCIF_STREAM_MODE_TOISP; + else + capture_mode = RKCIF_STREAM_MODE_TOISP_RDBK; + } + if (cif_dev->active_sensor && + (cif_dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + cif_dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY || + cif_dev->active_sensor->mbus.type == V4L2_MBUS_CCP2)) + ret = rkcif_csi_stream_start(stream, capture_mode); else - ret = rkcif_stream_start(stream); + ret = rkcif_stream_start(stream, capture_mode); if (ret) { v4l2_err(&cif_dev->v4l2_dev, "%s:resume stream[%d] failed\n", __func__, stream->id); goto unlock_stream; } - atomic_inc(&p->stream_cnt); - stream->streamon_timestamp = ktime_get_ns(); + v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, "resume stream[%d], frm_idx:%d, csi_sof:%d\n", stream->id, stream->frame_idx, rkcif_get_sof(cif_dev)); } - if (!stream_on_cnt) - return 0; + + rockchip_set_system_status(SYS_STATUS_CIF0); + on = 1; for (i = 0; i < p->num_subdevs; i++) { @@ -5534,9 +9201,7 @@ rkcif_set_sof(cif_dev, resume_info->frm_sync_seq); - if (reset_src == RKCIF_RESET_SRC_ERR_CSI2 || - reset_src == RKCIF_RESET_SRC_ERR_HOTPLUG || - reset_src == RKICF_RESET_SRC_ERR_CUTOFF) { + if (reset_src != RKCIF_RESET_SRC_ERR_APP) { ret = v4l2_subdev_call(p->subdevs[i], core, ioctl, RKMODULE_SET_QUICK_STREAM, &on); if (ret) @@ -5544,6 +9209,11 @@ "quick stream on subdev:%s failed\n", p->subdevs[i]->name); } + } else { + if (p->subdevs[i] == terminal_sensor->sd) + rkcif_set_sof(cif_dev, resume_info->frm_sync_seq); + + ret = v4l2_subdev_call(p->subdevs[i], video, s_stream, on); } if (ret) @@ -5551,68 +9221,28 @@ p->subdevs[i]->name); } - rkcif_start_luma(&cif_dev->luma_vdev, resume_stream[0]->cif_fmt_in); + if (priv && priv->is_combine_mode && cif_dev->sditf_cnt <= RKCIF_MAX_SDITF) { + for (i = 0; i < cif_dev->sditf_cnt; i++) { + if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd) + v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, ioctl, + RKMODULE_SET_QUICK_STREAM, &on); + } + } + + if (cif_dev->chip_id < CHIP_RK3588_CIF) + rkcif_start_luma(&cif_dev->luma_vdev, + cif_dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in); timer->csi2_err_triggered_cnt = 0; + rkcif_monitor_reset_event(cif_dev); v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, "do rkcif reset successfully!\n"); - + mutex_unlock(&cif_dev->stream_lock); return 0; unlock_stream: + mutex_unlock(&cif_dev->stream_lock); return ret; -} - -static int rkcif_do_reset_work(struct rkcif_device *cif_dev, - enum rkmodule_reset_src reset_src) -{ - struct rkcif_stream *resume_stream[RKCIF_MAX_DEV][RKCIF_MAX_STREAM_MIPI] = {0}; - struct rkcif_resume_info *resume_info[RKCIF_MAX_DEV]; - struct rkcif_hw *hw = cif_dev->hw_dev; - struct rkcif_device *cifdev = NULL; - int i = 0; - int ret = 0; - - v4l2_info(&cif_dev->v4l2_dev, "do rkcif reset\n"); - - mutex_lock(&cif_dev->hw_dev->dev_lock); - if (hw->reset_work_cancel) { - mutex_unlock(&hw->dev_lock); - return 0; - } - for (i = 0; i < hw->dev_num; i++) { - cifdev = hw->cif_dev[i]; - resume_info[i] = &cifdev->reset_work.resume_info; - ret |= rkcif_streamoff_in_reset(cifdev, - resume_stream[i], - resume_info[i], - reset_src); - } - - rockchip_clear_system_status(SYS_STATUS_CIF0); - - rkcif_do_cru_reset(cif_dev); - - udelay(30); - - for (i = 0; i < hw->dev_num; i++) { - cifdev = hw->cif_dev[i]; - resume_info[i] = &cifdev->reset_work.resume_info; - ret |= rkcif_streamon_in_reset(cifdev, - resume_stream[i], - resume_info[i], - reset_src); - } - - rockchip_set_system_status(SYS_STATUS_CIF0); - - hw->hw_timer.is_running = false; - rkcif_monitor_reset_event(cif_dev->hw_dev); - - v4l2_info(&cif_dev->v4l2_dev, "do rkcif reset successfully!\n"); - mutex_unlock(&hw->dev_lock); - return ret; - } void rkcif_reset_work(struct work_struct *work) @@ -5630,130 +9260,183 @@ v4l2_info(&dev->v4l2_dev, "do reset work failed!\n"); } -static bool rkcif_is_stream_stop_output(struct rkcif_stream *stream) +static bool rkcif_is_reduced_frame_rate(struct rkcif_device *dev) { - struct rkcif_device *dev = stream->cifdev; - struct rkcif_hw_timer *hw_timer = &dev->hw_dev->hw_timer; - struct rkcif_stream *tmp_stream = NULL; + struct rkcif_timer *timer = &dev->reset_watchdog_timer; + struct rkcif_stream *stream = &dev->stream[RKCIF_STREAM_MIPI_ID0]; struct v4l2_rect *raw_rect = &dev->terminal_sensor.raw_rect; - u64 fps, diff_time; - unsigned int i; - s64 vblank_def = 0; - s32 vblank = 0; - u64 numerator = 0; - u64 denominator = 0; - u64 cur_timestamp = 0; + u64 fps, timestamp0, timestamp1, diff_time; + unsigned long fps_flags; + unsigned int deviation = 1; + bool is_reduced = false; + u64 cur_time = 0; + u64 time_distance = 0; - if (dev->hdr.mode == HDR_X3) { - for (i = 0; i < 3; i++) { - tmp_stream = &dev->stream[i]; - if (tmp_stream->state != RKCIF_STATE_STREAMING) - return false; - } - } else if (dev->hdr.mode == HDR_X2) { - for (i = 0; i < 2; i++) { - tmp_stream = &dev->stream[i]; - if (tmp_stream->state != RKCIF_STATE_STREAMING) - return false; - } - } + spin_lock_irqsave(&stream->fps_lock, fps_flags); + timestamp0 = stream->fps_stats.frm0_timestamp; + timestamp1 = stream->fps_stats.frm1_timestamp; + spin_unlock_irqrestore(&stream->fps_lock, fps_flags); - vblank_def = rkcif_get_sensor_vblank_def(dev); - vblank = rkcif_get_sensor_vblank(dev); - numerator = dev->terminal_sensor.fi.interval.numerator; - denominator = dev->terminal_sensor.fi.interval.denominator; - fps = div_u64(1000 * numerator, denominator); - fps *= (raw_rect->height + vblank); - fps = div_u64((raw_rect->height + vblank_def), fps); + fps = timestamp0 > timestamp1 ? + timestamp0 - timestamp1 : timestamp1 - timestamp0; + fps = div_u64(fps, 1000); + diff_time = fps > timer->frame_end_cycle_us ? + fps - timer->frame_end_cycle_us : 0; + deviation = DIV_ROUND_UP(timer->vts, 100); - if (fps > hw_timer->monitor_cycle) { - v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "camera work in long expsure, not to check stream loss\n"); + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "diff_time:%lld,devi_t:%ld,devi_h:%d\n", + diff_time, timer->line_end_cycle * deviation, deviation); + + cur_time = ktime_get_ns(); + time_distance = timestamp0 > timestamp1 ? + cur_time - timestamp0 : cur_time - timestamp1; + time_distance = div_u64(time_distance, 1000); + if (time_distance > fps * 2) return false; + + if (diff_time > timer->line_end_cycle * deviation) { + s32 vblank = 0; + unsigned int vts; + + is_reduced = true; + vblank = rkcif_get_sensor_vblank(dev); + vts = vblank + timer->raw_height; + + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "old vts:%d,new vts:%d\n", timer->vts, vts); + + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, + "reduce frame rate,vblank:%d, height(raw output):%d, fps:%lld, frm_end_t:%ld, line_t:%ld, diff:%lld\n", + rkcif_get_sensor_vblank(dev), + raw_rect->height, + fps, + timer->frame_end_cycle_us, + timer->line_end_cycle, + diff_time); + + timer->vts = vts; + timer->frame_end_cycle_us = fps; + timer->line_end_cycle = div_u64(timer->frame_end_cycle_us, timer->vts); + } else { + is_reduced = false; } - cur_timestamp = ktime_get_ns(); - diff_time = cur_timestamp - stream->streamon_timestamp; - diff_time = div_u64(diff_time, 1000000); - if (diff_time > hw_timer->monitor_cycle + 10) - return true; + timer->frame_end_cycle_us = fps; - return false; + fps = div_u64(fps, 1000); + fps = fps * timer->frm_num_of_monitor_cycle; + timer->cycle = msecs_to_jiffies(fps); + timer->timer.expires = jiffies + timer->cycle; + + return is_reduced; + } -static void rkcif_init_reset_work(struct rkcif_hw_timer *hw_timer) +static void rkcif_dvp_event_reset_pipe(struct rkcif_device *dev, int reset_src) { - struct rkcif_hw *hw = container_of(hw_timer, - struct rkcif_hw, - hw_timer); - struct rkcif_device *dev = NULL; + struct rkcif_dvp_sof_subdev *subdev = &dev->dvp_sof_subdev; + + if (subdev) { + struct v4l2_event event = { + .type = V4L2_EVENT_RESET_DEV, + .reserved[0] = reset_src, + }; + v4l2_event_queue(subdev->sd.devnode, &event); + } +} + +static void rkcif_lvds_event_reset_pipe(struct rkcif_device *dev, int reset_src) +{ + struct rkcif_lvds_subdev *subdev = &dev->lvds_subdev; + + if (subdev) { + struct v4l2_event event = { + .type = V4L2_EVENT_RESET_DEV, + .reserved[0] = reset_src, + }; + v4l2_event_queue(subdev->sd.devnode, &event); + } +} + +static void rkcif_send_reset_event(struct rkcif_device *cif_dev, int reset_src) +{ + struct v4l2_mbus_config *mbus = &cif_dev->active_sensor->mbus; + struct csi2_dev *csi; + + if (mbus->type == V4L2_MBUS_CSI2_DPHY || + mbus->type == V4L2_MBUS_CSI2_CPHY) { + csi = container_of(cif_dev->active_sensor->sd, struct csi2_dev, sd); + rkcif_csi2_event_reset_pipe(csi, reset_src); + } else if (mbus->type == V4L2_MBUS_CCP2) { + rkcif_lvds_event_reset_pipe(cif_dev, reset_src); + } else { + rkcif_dvp_event_reset_pipe(cif_dev, reset_src); + } + v4l2_dbg(3, rkcif_debug, &cif_dev->v4l2_dev, + "send reset event,bus type 0x%x\n", + mbus->type); +} + +static void rkcif_init_reset_work(struct rkcif_timer *timer) +{ + struct rkcif_device *dev = container_of(timer, + struct rkcif_device, + reset_watchdog_timer); struct rkcif_stream *stream = NULL; - struct rkcif_timer *timer; unsigned long flags; - int i = 0, j = 0; + int i = 0; v4l2_info(&dev->v4l2_dev, "do reset work schedule, run_cnt:%d, reset source:%d\n", - hw_timer->run_cnt, hw_timer->reset_src); + timer->run_cnt, timer->reset_src); - for (j = 0; j < hw->dev_num; j++) { - dev = hw->cif_dev[j]; - timer = &dev->reset_watchdog_timer; - spin_lock_irqsave(&timer->csi2_err_lock, flags); - timer->is_triggered = false; - timer->csi2_err_cnt_odd = 0; - timer->csi2_err_cnt_even = 0; - timer->csi2_err_fs_fe_cnt = 0; - timer->notifer_called_cnt = 0; - for (i = 0; i < dev->num_channels; i++) { - stream = &dev->stream[i]; - if (stream->state == RKCIF_STATE_STREAMING) - timer->last_buf_wakeup_cnt[stream->id] = stream->frame_idx; - } - spin_unlock_irqrestore(&timer->csi2_err_lock, flags); + spin_lock_irqsave(&timer->timer_lock, flags); + timer->is_running = false; + timer->is_triggered = false; + timer->csi2_err_cnt_odd = 0; + timer->csi2_err_cnt_even = 0; + timer->csi2_err_fs_fe_cnt = 0; + timer->notifer_called_cnt = 0; + for (i = 0; i < dev->num_channels; i++) { + stream = &dev->stream[i]; + if (stream->state == RKCIF_STATE_STREAMING) + timer->last_buf_wakeup_cnt[stream->id] = stream->buf_wake_up_cnt; } - if (hw_timer->is_reset_by_user) { - spin_lock_irqsave(&hw->spin_lock, flags); - hw->reset_info.is_need_reset = 1; - hw->reset_info.reset_src = hw_timer->reset_src; - spin_unlock_irqrestore(&hw->spin_lock, flags); + spin_unlock_irqrestore(&timer->timer_lock, flags); + if (timer->is_ctrl_by_user) { + rkcif_send_reset_event(dev, timer->reset_src); } else { - dev->reset_work.reset_src = hw_timer->reset_src; - if (schedule_work(&dev->reset_work.work)) { + if (!schedule_work(&dev->reset_work.work)) v4l2_info(&dev->v4l2_dev, - "schedule reset work successfully\n"); - } else { - v4l2_info(&dev->v4l2_dev, - "schedule reset work failed\n"); - } + "schedule reset work failed\n"); + dev->reset_work.reset_src = timer->reset_src; } } static int rkcif_detect_reset_event(struct rkcif_stream *stream, struct rkcif_timer *timer, - int *check_cnt, + int check_cnt, bool *is_mod_timer) { struct rkcif_device *dev = stream->cifdev; struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor; - struct rkcif_hw_timer *hw_timer = &dev->hw_dev->hw_timer; + unsigned long flags; int ret, is_reset = 0; struct rkmodule_vicap_reset_info rst_info; - v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, - "info: frame end still update(%d, %d), detect cnt: %d, mode:%d check_cnt:%d\n", - timer->last_buf_wakeup_cnt[stream->id], stream->frame_idx, - hw_timer->run_cnt, hw_timer->monitor_mode, *check_cnt); + if (timer->last_buf_wakeup_cnt[stream->id] < stream->buf_wake_up_cnt && + check_cnt == 0) { - if (timer->last_buf_wakeup_cnt[stream->id] < stream->frame_idx) { - *check_cnt += 1; v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, - "info: frame end still update(%d, %d), detect cnt: %d, mode:%d\n", + "info: frame end still update(%d, %d) in detecting cnt:%d, mode:%d\n", timer->last_buf_wakeup_cnt[stream->id], stream->frame_idx, - hw_timer->run_cnt, hw_timer->monitor_mode); + timer->run_cnt, timer->monitor_mode); - timer->last_buf_wakeup_cnt[stream->id] = stream->frame_idx; + timer->last_buf_wakeup_cnt[stream->id] = stream->buf_wake_up_cnt; - if (hw_timer->monitor_mode == RKCIF_MONITOR_MODE_HOTPLUG) { + if (stream->frame_idx > 2) + rkcif_is_reduced_frame_rate(dev); + + if (timer->monitor_mode == RKCIF_MONITOR_MODE_HOTPLUG) { ret = v4l2_subdev_call(terminal_sensor->sd, core, ioctl, RKMODULE_GET_VICAP_RST_INFO, @@ -5763,156 +9446,139 @@ else is_reset = rst_info.is_reset; rst_info.is_reset = 0; - hw_timer->reset_src = RKCIF_RESET_SRC_ERR_HOTPLUG; + if (is_reset) + timer->reset_src = RKCIF_RESET_SRC_ERR_HOTPLUG; v4l2_subdev_call(terminal_sensor->sd, core, ioctl, RKMODULE_SET_VICAP_RST_INFO, &rst_info); - if (!is_reset && stream->cifdev->inf_id == RKCIF_MIPI_LVDS) { - hw_timer->reset_src = RKICF_RESET_SRC_ERR_CUTOFF; + if (!is_reset) { is_reset = rkcif_is_csi2_err_trigger_reset(timer); - } - } else if (hw_timer->monitor_mode == RKCIF_MONITOR_MODE_CONTINUE) { - if (stream->cifdev->inf_id == RKCIF_MIPI_LVDS) - is_reset = rkcif_is_csi2_err_trigger_reset(timer); - } else if (hw_timer->monitor_mode == RKCIF_MONITOR_MODE_TRIGGER) { - if (stream->cifdev->inf_id == RKCIF_MIPI_LVDS) { - is_reset = timer->is_csi2_err_occurred; if (is_reset) - hw_timer->reset_src = RKCIF_RESET_SRC_ERR_CSI2; - timer->is_csi2_err_occurred = false; + timer->reset_src = RKCIF_RESET_SRC_ERR_CSI2; } + } else if (timer->monitor_mode == RKCIF_MONITOR_MODE_CONTINUE) { + is_reset = rkcif_is_csi2_err_trigger_reset(timer); + } else if (timer->monitor_mode == RKCIF_MONITOR_MODE_TRIGGER) { + is_reset = timer->is_csi2_err_occurred; + if (is_reset) + timer->reset_src = RKCIF_RESET_SRC_ERR_CSI2; + timer->is_csi2_err_occurred = false; } if (is_reset) { - rkcif_init_reset_work(hw_timer); + rkcif_init_reset_work(timer); return is_reset; } - *is_mod_timer = true; - } else if (timer->last_buf_wakeup_cnt[stream->id] == stream->frame_idx) { - bool is_loss_stream = false; - *check_cnt += 1; - if (hw_timer->run_cnt > 4) - is_loss_stream = rkcif_is_stream_stop_output(stream); - - if (is_loss_stream) { - v4l2_info(&dev->v4l2_dev, - "do reset work due to frame end is stopped, run_cnt:%d\n", - hw_timer->run_cnt); - - hw_timer->reset_src = RKICF_RESET_SRC_ERR_CUTOFF; - is_reset = true; - rkcif_init_reset_work(hw_timer); + if (timer->monitor_mode == RKCIF_MONITOR_MODE_CONTINUE || + timer->monitor_mode == RKCIF_MONITOR_MODE_HOTPLUG) { + if (timer->run_cnt == timer->max_run_cnt) + timer->run_cnt = 0x0; + *is_mod_timer = true; } else { + if (timer->run_cnt <= timer->max_run_cnt) { + *is_mod_timer = true; + } else { + spin_lock_irqsave(&timer->timer_lock, flags); + timer->is_triggered = false; + timer->is_running = false; + spin_unlock_irqrestore(&timer->timer_lock, flags); + v4l2_info(&dev->v4l2_dev, "stop reset detecting!\n"); + } + } + } else if (timer->last_buf_wakeup_cnt[stream->id] == stream->buf_wake_up_cnt) { + + bool is_reduced = false; + + if (stream->frame_idx > 2) + is_reduced = rkcif_is_reduced_frame_rate(dev); + else if (timer->run_cnt < 20) + is_reduced = true; + + if (is_reduced) { *is_mod_timer = true; v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "%s fps is reduced\n", __func__); + } else { + + v4l2_info(&dev->v4l2_dev, + "do reset work due to frame end is stopped, run_cnt:%d\n", + timer->run_cnt); + + timer->reset_src = RKICF_RESET_SRC_ERR_CUTOFF; + rkcif_init_reset_work(timer); + is_reset = true; } } - return is_reset; - -} - -static int rkcif_dvp_err_trigger_reset(struct rkcif_device *dev) -{ - int is_reset = 0; - - if (dev->irq_stats.dvp_overflow_cnt) { - dev->irq_stats.dvp_overflow_cnt = 0; - is_reset = 1; - } - return is_reset; -} - -static int rkcif_detect_reset_event_all_dev(struct rkcif_device *dev, - int *check_cnt, - bool *is_mod_timer) -{ - struct rkcif_timer *timer = &dev->reset_watchdog_timer; - struct rkcif_stream *stream = NULL; - int i = 0; - int is_reset = 0; - int check_cnt_local = 0; - - for (i = 0; i < dev->num_channels; i++) { - stream = &dev->stream[i]; - if (stream->state == RKCIF_STATE_STREAMING) { - is_reset = rkcif_detect_reset_event(stream, - timer, - &check_cnt_local, - is_mod_timer); - if (is_reset) - break; - } - } - if (!is_reset && dev->inf_id == RKCIF_DVP) - is_reset = rkcif_dvp_err_trigger_reset(dev); - - if (check_cnt_local) - *check_cnt += 1; return is_reset; } void rkcif_reset_watchdog_timer_handler(struct timer_list *t) { - struct rkcif_hw_timer *hw_timer = container_of(t, struct rkcif_hw_timer, timer); - struct rkcif_hw *hw = container_of(hw_timer, - struct rkcif_hw, - hw_timer); - struct rkcif_device *dev = NULL; + struct rkcif_timer *timer = container_of(t, struct rkcif_timer, timer); + struct rkcif_device *dev = container_of(timer, + struct rkcif_device, + reset_watchdog_timer); + struct rkcif_stream *stream = NULL; unsigned long flags; unsigned int i; int is_reset = 0; int check_cnt = 0; bool is_mod_timer = false; - struct rkmodule_vicap_reset_info rst_info; - for (i = 0; i < hw->dev_num; i++) { - dev = hw->cif_dev[i]; - is_reset = rkcif_detect_reset_event_all_dev(dev, - &check_cnt, + for (i = 0; i < dev->num_channels; i++) { + stream = &dev->stream[i]; + if (stream->state == RKCIF_STATE_STREAMING) { + is_reset = rkcif_detect_reset_event(stream, + timer, + check_cnt, &is_mod_timer); - if (is_reset) - break; - } - - if (hw_timer->monitor_mode == RKCIF_MONITOR_MODE_HOTPLUG && is_reset) { - for (i = 0; i < hw->dev_num; i++) { - dev = hw->cif_dev[i]; - rst_info.is_reset = 0; - if (dev->terminal_sensor.sd) - v4l2_subdev_call(dev->terminal_sensor.sd, core, ioctl, - RKMODULE_SET_VICAP_RST_INFO, &rst_info); + check_cnt++; + if (is_reset) + break; } } - if (!is_reset && is_mod_timer) - mod_timer(&hw_timer->timer, jiffies + hw_timer->cycle_jif); + mod_timer(&timer->timer, jiffies + timer->cycle); - hw_timer->run_cnt += 1; + timer->run_cnt += 1; - if (!check_cnt && !is_reset) { - spin_lock_irqsave(&hw_timer->timer_lock, flags); - hw_timer->is_running = false; - spin_unlock_irqrestore(&hw_timer->timer_lock, flags); + if (!check_cnt) { + spin_lock_irqsave(&timer->timer_lock, flags); + timer->is_triggered = false; + timer->is_running = false; + spin_unlock_irqrestore(&timer->timer_lock, flags); - dev_info(hw->dev, - "all stream is stopped, stop reset detect!\n"); + v4l2_info(&dev->v4l2_dev, + "all stream is stopped, stop reset detect!\n"); } } int rkcif_reset_notifier(struct notifier_block *nb, unsigned long action, void *data) { - struct rkcif_device *dev = container_of(nb, struct rkcif_device, reset_notifier); - struct rkcif_timer *timer = &dev->reset_watchdog_timer; - struct rkcif_hw_timer *hw_timer = &dev->hw_dev->hw_timer; + struct rkcif_hw *hw = container_of(nb, struct rkcif_hw, reset_notifier); + struct rkcif_device *dev = NULL; + struct rkcif_timer *timer = NULL; unsigned long flags, val; + u32 *csi_idx = data; + int i = 0; + bool is_match_dev = false; - if (hw_timer->is_running) { + for (i = 0; i < hw->dev_num; i++) { + dev = hw->cif_dev[i]; + if (*csi_idx == dev->csi_host_idx) { + is_match_dev = true; + break; + } + } + if (!is_match_dev) + return -EINVAL; + timer = &dev->reset_watchdog_timer; + if (timer->is_running) { val = action & CSI2_ERR_COUNT_ALL_MASK; spin_lock_irqsave(&timer->csi2_err_lock, flags); - if ((val % hw_timer->err_ref_cnt) == 0) { + if ((val % timer->csi2_err_ref_cnt) == 0) { timer->notifer_called_cnt++; if ((timer->notifer_called_cnt % 2) == 0) timer->csi2_err_cnt_even = val; @@ -5930,7 +9596,12 @@ static void rkcif_modify_line_int(struct rkcif_stream *stream, bool en) { struct rkcif_device *cif_dev = stream->cifdev; + u32 line_intr_en = 0; + if (cif_dev->chip_id >= CHIP_RK3588_CIF) + line_intr_en = CSI_LINE_INTEN_RK3588(stream->id); + else + line_intr_en = CSI_LINE_INTEN(stream->id); if (en) { if (cif_dev->wait_line_bak != cif_dev->wait_line) { cif_dev->wait_line_bak = cif_dev->wait_line; @@ -5940,44 +9611,73 @@ cif_dev->wait_line << 16 | cif_dev->wait_line); } rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_INTEN, - CSI_LINE_INTEN(stream->id)); + line_intr_en); + stream->is_line_inten = true; } else { rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN, - ~(CSI_LINE_INTEN(stream->id))); + ~line_intr_en); } } static void rkcif_detect_wake_up_mode_change(struct rkcif_stream *stream) { struct rkcif_device *cif_dev = stream->cifdev; + struct sditf_priv *priv = cif_dev->sditf[0]; + bool is_change = false; + int ch = 0; + int i = 0; + + if (!priv || priv->mode.rdbk_mode == RKISP_VICAP_ONLINE) + return; + + if ((cif_dev->hdr.hdr_mode == NO_HDR || cif_dev->hdr.hdr_mode == HDR_COMPR) && + stream->id == RKCIF_STREAM_MIPI_ID0) { + if (cif_dev->wait_line != cif_dev->wait_line_cache) + cif_dev->wait_line = cif_dev->wait_line_cache; + } else if (cif_dev->hdr.hdr_mode == HDR_X2 && stream->id == RKCIF_STREAM_MIPI_ID1) { + if (cif_dev->wait_line != cif_dev->wait_line_cache) + cif_dev->wait_line = cif_dev->wait_line_cache; + } else if (cif_dev->hdr.hdr_mode == HDR_X3 && stream->id == RKCIF_STREAM_MIPI_ID2) { + if (cif_dev->wait_line != cif_dev->wait_line_cache) + cif_dev->wait_line = cif_dev->wait_line_cache; + } if (cif_dev->wait_line && (!stream->is_line_wake_up)) { + is_change = true; stream->is_line_wake_up = true; if (stream->frame_phase == CIF_CSI_FRAME0_READY) stream->line_int_cnt = 1; else if (stream->frame_phase == CIF_CSI_FRAME1_READY) stream->line_int_cnt = 0; + if (cif_dev->hdr.hdr_mode == HDR_X2) { + cif_dev->stream[0].is_line_wake_up = true; + cif_dev->stream[0].line_int_cnt = stream->line_int_cnt; + } else if (cif_dev->hdr.hdr_mode == HDR_X3) { + cif_dev->stream[0].is_line_wake_up = true; + cif_dev->stream[1].is_line_wake_up = true; + cif_dev->stream[0].line_int_cnt = stream->line_int_cnt; + cif_dev->stream[1].line_int_cnt = stream->line_int_cnt; + } } else if ((cif_dev->wait_line == 0) && stream->is_line_wake_up) { stream->is_line_wake_up = false; } if (stream->is_line_wake_up) { - rkcif_modify_line_int(stream, true); - stream->is_line_inten = true; - } - - if (cif_dev->hdr.mode == NO_HDR && stream->id == RKCIF_STREAM_MIPI_ID0) { - if (cif_dev->wait_line != cif_dev->wait_line_cache) - cif_dev->wait_line = cif_dev->wait_line_cache; - } else if (cif_dev->hdr.mode == HDR_X2 && stream->id == RKCIF_STREAM_MIPI_ID1) { - if (cif_dev->wait_line != cif_dev->wait_line_cache) - cif_dev->wait_line = cif_dev->wait_line_cache; - } else if (cif_dev->hdr.mode == HDR_X3 && stream->id == RKCIF_STREAM_MIPI_ID2) { - if (cif_dev->wait_line != cif_dev->wait_line_cache) - cif_dev->wait_line = cif_dev->wait_line_cache; + if (is_change) { + if (cif_dev->hdr.hdr_mode == HDR_X2) + ch = 2; + else if (cif_dev->hdr.hdr_mode == HDR_X3) + ch = 3; + else + ch = 1; + for (i = 0; i < ch; i++) + rkcif_modify_line_int(&cif_dev->stream[i], true); + } else { + rkcif_modify_line_int(stream, true); + } } } -static u32 rkisp_mbus_pixelcode_to_v4l2(u32 pixelcode) +u32 rkcif_mbus_pixelcode_to_v4l2(u32 pixelcode) { u32 pixelformat; @@ -6066,13 +9766,14 @@ v4l2_subdev_call(cif_dev->terminal_sensor.sd, pad, get_fmt, NULL, &fmt); memset(&pixm, 0, sizeof(pixm)); - pixm.pixelformat = rkisp_mbus_pixelcode_to_v4l2(fmt.format.code); + pixm.pixelformat = rkcif_mbus_pixelcode_to_v4l2(fmt.format.code); pixm.width = fmt.format.width; pixm.height = fmt.format.height; memset(&input_sel, 0, sizeof(input_sel)); input_sel.pad = i; input_sel.target = V4L2_SEL_TGT_CROP_BOUNDS; + input_sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; ret = v4l2_subdev_call(cif_dev->terminal_sensor.sd, pad, get_selection, NULL, &input_sel); @@ -6085,13 +9786,899 @@ } } -#define CSI_START_INTSTAT(id) (0x3 << ((id) * 2)) +void rkcif_enable_dma_capture(struct rkcif_stream *stream, bool is_only_enable) +{ + struct rkcif_device *cif_dev = stream->cifdev; + struct v4l2_mbus_config *mbus_cfg = &cif_dev->active_sensor->mbus; + struct csi_channel_info *channel = &cif_dev->channels[stream->id]; + u32 val = 0; + + if (stream->buf_owner == RKCIF_DMAEN_BY_ISP) + stream->buf_owner = RKCIF_DMAEN_BY_ISP_TO_VICAP; + + if (stream->dma_en) { + stream->dma_en |= stream->to_en_dma; + stream->to_en_dma = 0; + return; + } + + stream->dma_en |= stream->to_en_dma; + if (!is_only_enable) { + if (stream->to_en_dma == RKCIF_DMAEN_BY_VICAP) { + rkcif_assign_new_buffer_pingpong(stream, + RKCIF_YUV_ADDR_STATE_INIT, + stream->id); + rkcif_write_register(cif_dev, get_reg_index_of_frm0_y_vlw(stream->id), + channel->virtual_width); + } else if (stream->to_en_dma == RKCIF_DMAEN_BY_ISP) { + rkcif_assign_new_buffer_pingpong_toisp(stream, + RKCIF_YUV_ADDR_STATE_INIT, + stream->id); + } + } + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY) + rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_CTRL, 0x00010000); + else + rkcif_write_register_or(cif_dev, CIF_REG_DVP_CTRL, 0x00010000); + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY) { + val = rkcif_read_register(cif_dev, get_reg_index_of_id_ctrl0(stream->id)); + if (!stream->is_compact) + val |= CSI_WRDDR_TYPE_RAW_UNCOMPACT; + else + val &= ~CSI_WRDDR_TYPE_RAW_UNCOMPACT; + val |= CSI_DMA_ENABLE; + rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(stream->id), val); + } else if (mbus_cfg->type == V4L2_MBUS_CCP2) { + val = rkcif_read_register(cif_dev, get_reg_index_of_lvds_id_ctrl0(stream->id)); + if (!stream->is_compact) + val |= CSI_WRDDR_TYPE_RAW_UNCOMPACT << 17; + else + val &= ~(CSI_WRDDR_TYPE_RAW_UNCOMPACT << 17); + val |= LVDS_DMAEN_RV1106; + rkcif_write_register(cif_dev, get_reg_index_of_lvds_id_ctrl0(stream->id), val); + } else { + val = rkcif_read_register(cif_dev, CIF_REG_DVP_FOR); + if (!stream->is_compact) + val |= CSI_WRDDR_TYPE_RAW_UNCOMPACT << 11; + else + val &= ~(CSI_WRDDR_TYPE_RAW_UNCOMPACT << 11); + rkcif_write_register(cif_dev, CIF_REG_DVP_FOR, val); + val = rkcif_read_register(cif_dev, CIF_REG_DVP_CTRL); + if (cif_dev->chip_id == CHIP_RK3588_CIF) + val |= DVP_DMA_EN; + else if (cif_dev->chip_id == CHIP_RV1106_CIF) + val |= DVP_SW_DMA_EN(stream->id); + rkcif_write_register(cif_dev, CIF_REG_DVP_CTRL, val); + } + + stream->to_en_dma = 0; +} + +static int rkcif_stop_dma_capture(struct rkcif_stream *stream) +{ + struct rkcif_device *cif_dev = stream->cifdev; + struct v4l2_mbus_config *mbus_cfg = &cif_dev->active_sensor->mbus; + u32 val = 0; + + if (stream->buf_replace_cnt) + return -EINVAL; + + stream->dma_en &= ~stream->to_stop_dma; + + if (stream->dma_en != 0) { + if (stream->dma_en & RKCIF_DMAEN_BY_ISP) + stream->buf_owner = RKCIF_DMAEN_BY_ISP; + stream->to_stop_dma = 0; + return 0; + } + + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY) { + val = rkcif_read_register(cif_dev, get_reg_index_of_id_ctrl0(stream->id)); + val &= ~CSI_DMA_ENABLE; + if (stream->is_stop_capture) { + val &= ~CSI_ENABLE_CAPTURE; + stream->is_stop_capture = false; + } + rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(stream->id), val); + } else if (mbus_cfg->type == V4L2_MBUS_CCP2) { + val = rkcif_read_register(cif_dev, get_reg_index_of_lvds_id_ctrl0(stream->id)); + val &= ~LVDS_DMAEN_RV1106; + if (stream->is_stop_capture) { + val &= ~ENABLE_CAPTURE; + stream->is_stop_capture = false; + } + rkcif_write_register(cif_dev, get_reg_index_of_lvds_id_ctrl0(stream->id), val); + } else { + val = rkcif_read_register(cif_dev, CIF_REG_DVP_CTRL); + if (cif_dev->chip_id == CHIP_RK3588_CIF) + val &= ~DVP_DMA_EN; + else if (cif_dev->chip_id == CHIP_RV1106_CIF) + val &= ~(DVP_SW_DMA_EN(stream->id)); + if (stream->is_stop_capture) { + val &= ~ENABLE_CAPTURE; + stream->is_stop_capture = false; + } + rkcif_write_register(cif_dev, CIF_REG_DVP_CTRL, val); + } + stream->to_stop_dma = 0; + v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev, + "stream[%d] replace_cnt %d, y_addr 0x%x, 0x%x\n", + stream->id, stream->buf_replace_cnt, + rkcif_read_register(cif_dev, get_reg_index_of_frm0_y_addr(stream->id)), + rkcif_read_register(cif_dev, get_reg_index_of_frm1_y_addr(stream->id))); + return 0; +} + +static void rkcif_send_sof(struct rkcif_device *cif_dev) +{ + struct v4l2_mbus_config *mbus = &cif_dev->active_sensor->mbus; + struct csi2_dev *csi; + + if (mbus->type == V4L2_MBUS_CSI2_DPHY || + mbus->type == V4L2_MBUS_CSI2_CPHY) { + csi = container_of(cif_dev->active_sensor->sd, struct csi2_dev, sd); + rkcif_csi2_event_inc_sof(csi); + } else if (mbus->type == V4L2_MBUS_CCP2) { + rkcif_lvds_event_inc_sof(cif_dev); + } else { + rkcif_dvp_event_inc_sof(cif_dev); + } +} + +static int rkcif_g_toisp_ch(unsigned int intstat_glb, int index) +{ + if (intstat_glb & TOISP_END_CH0(index)) + return RKCIF_TOISP_CH0; + if (intstat_glb & TOISP_END_CH1(index)) + return RKCIF_TOISP_CH1; + if (intstat_glb & TOISP_END_CH2(index)) + return RKCIF_TOISP_CH2; + + return -EINVAL; +} + +static int rkcif_g_toisp_fs(unsigned int intstat_glb, int index) +{ + if (intstat_glb & TOISP_FS_CH0(index)) + return RKCIF_TOISP_CH0; + if (intstat_glb & TOISP_FS_CH1(index)) + return RKCIF_TOISP_CH1; + if (intstat_glb & TOISP_FS_CH2(index)) + return RKCIF_TOISP_CH2; + + return -EINVAL; +} + +static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, + unsigned int intstat_glb, + int index) +{ + int ch = 0; + struct rkcif_stream *stream; + int src_id = 0; + int i = 0; + u32 val = 0; + u64 cur_time = 0; + + for (i = 0; i < TOISP_CH_MAX; i++) { + ch = rkcif_g_toisp_ch(intstat_glb, index); + if (ch >= 0) { + src_id = priv->toisp_inf.ch_info[ch].id; + if (src_id == 24) + stream = &priv->cif_dev->stream[0]; + else + stream = &priv->cif_dev->stream[src_id % 4]; + if (stream->stopping) { + v4l2_dbg(3, rkcif_debug, &priv->cif_dev->v4l2_dev, + "stream[%d] stop\n", + stream->id); + rkcif_stream_stop(stream); + stream->stopping = false; + wake_up(&stream->wq_stopped); + } + + if (stream->cifdev->chip_id >= CHIP_RV1106_CIF) + rkcif_modify_frame_skip_config(stream); + if (stream->cifdev->rdbk_debug && + stream->frame_idx < 15) + v4l2_info(&priv->cif_dev->v4l2_dev, + "stream[%d] toisp fe %d\n", + stream->id, + stream->frame_idx - 1); + + switch (ch) { + case RKCIF_TOISP_CH0: + val = TOISP_END_CH0(index); + intstat_glb = intstat_glb & (~val); + break; + case RKCIF_TOISP_CH1: + val = TOISP_END_CH1(index); + intstat_glb = intstat_glb & (~val); + break; + case RKCIF_TOISP_CH2: + val = TOISP_END_CH2(index); + intstat_glb = intstat_glb & (~val); + break; + default: + break; + } + } + ch = rkcif_g_toisp_fs(intstat_glb, index); + if (ch >= 0) { + src_id = priv->toisp_inf.ch_info[ch].id; + if (src_id == 24) + stream = &priv->cif_dev->stream[0]; + else + stream = &priv->cif_dev->stream[src_id % 4]; + if (stream->id == 0) + rkcif_send_sof(stream->cifdev); + stream->frame_idx++; + cur_time = ktime_get_ns(); + stream->readout.readout_time = cur_time - stream->readout.fs_timestamp; + stream->readout.fs_timestamp = cur_time; + if (stream->cifdev->rdbk_debug && + stream->frame_idx < 15) + v4l2_info(&priv->cif_dev->v4l2_dev, + "stream[%d] toisp sof seq %d\n", + stream->id, + stream->frame_idx - 1); + if (stream->to_en_dma) + rkcif_enable_dma_capture(stream, false); + if (stream->to_en_scale) { + stream->to_en_scale = false; + rkcif_scale_start(stream->scale_vdev); + } + switch (ch) { + case RKCIF_TOISP_CH0: + val = TOISP_FS_CH0(index); + intstat_glb = intstat_glb & (~val); + break; + case RKCIF_TOISP_CH1: + val = TOISP_FS_CH1(index); + intstat_glb = intstat_glb & (~val); + break; + case RKCIF_TOISP_CH2: + val = TOISP_FS_CH2(index); + intstat_glb = intstat_glb & (~val); + break; + default: + break; + } + } + } +} + +void rkcif_irq_handle_toisp(struct rkcif_device *cif_dev, unsigned int intstat_glb) +{ + int i = 0; + bool to_check = false; + struct sditf_priv *priv = cif_dev->sditf[0]; + + if (!priv || priv->mode.rdbk_mode != RKISP_VICAP_ONLINE) + return; + + for (i = 0; i < 2; i++) { + if (priv->toisp_inf.link_mode == TOISP0 && + i == 0) { + to_check = true; + } else if (priv->toisp_inf.link_mode == TOISP1 && + i == 1) { + to_check = true; + } else if (priv->toisp_inf.link_mode == TOISP_UNITE && + i == 1) { + to_check = true; + } + if (to_check) + rkcif_toisp_check_stop_status(priv, intstat_glb, i); + } +} + +static int rkcif_check_group_sync_state(struct rkcif_device *cif_dev) +{ + struct rkcif_stream *detect_stream = &cif_dev->stream[0]; + struct rkcif_stream *next_stream = NULL; + struct rkcif_hw *hw = cif_dev->hw_dev; + u64 fs_interval = 0; + int i = 0; + int ret = 0; + struct rkcif_multi_sync_config *sync_config; + + sync_config = &hw->sync_config[cif_dev->sync_cfg.group]; + sync_config->sync_code |= BIT(cif_dev->csi_host_idx); + v4l2_dbg(3, rkcif_debug, &cif_dev->v4l2_dev, + "sync code 0x%x, mask 0x%x, update 0x%x, cache 0x%x, timestamp %llu\n", + sync_config->sync_code, + sync_config->sync_mask, + sync_config->update_code, + sync_config->update_cache, + detect_stream->readout.fs_timestamp); + + if (sync_config->sync_code != sync_config->sync_mask) + return -EINVAL; + + for (i = 0; i < sync_config->dev_cnt; i++) { + if (sync_config->mode == RKCIF_MASTER_MASTER) { + if (i < sync_config->ext_master.count) + next_stream = &sync_config->ext_master.cif_dev[i]->stream + [0]; + else + next_stream = &sync_config->int_master.cif_dev[0]->stream + [0]; + } else if (sync_config->mode == RKCIF_MASTER_SLAVE) { + if (i < sync_config->slave.count) + next_stream = &sync_config->slave.cif_dev[i]->stream + [0]; + else + next_stream = &sync_config->int_master.cif_dev[0]->stream + [0]; + } else { + v4l2_err(&cif_dev->v4l2_dev, + "ERROR: invalid group sync mode\n"); + ret = -EINVAL; + break; + } + if (detect_stream == next_stream) + continue; + fs_interval = abs(detect_stream->readout.fs_timestamp - next_stream->readout.fs_timestamp); + if (fs_interval > RKCIF_MAX_INTERVAL_NS) { + ret = -EINVAL; + break; + } + } + return ret; +} + +static void rkcif_deal_sof(struct rkcif_device *cif_dev) +{ + struct rkcif_stream *detect_stream = &cif_dev->stream[0]; + struct rkcif_hw *hw = cif_dev->hw_dev; + struct rkcif_device *tmp_dev = NULL; + unsigned long flags; + int i = 0; + int ret = 0; + + if (cif_dev->chip_id < CHIP_RK3588_CIF) + detect_stream->fs_cnt_in_single_frame++; + spin_lock_irqsave(&detect_stream->fps_lock, flags); + detect_stream->readout.fs_timestamp = ktime_get_ns(); + spin_unlock_irqrestore(&detect_stream->fps_lock, flags); + + if (cif_dev->sync_cfg.type != RKCIF_NOSYNC_MODE) { + struct rkcif_multi_sync_config *sync_config; + + sync_config = &hw->sync_config[cif_dev->sync_cfg.group]; + ret = rkcif_check_group_sync_state(cif_dev); + if (!ret) { + sync_config->sync_code = 0; + sync_config->frame_idx++; + spin_lock_irqsave(&hw->group_lock, flags); + sync_config->update_cache = sync_config->sync_mask; + if (!sync_config->update_code) { + sync_config->update_code = sync_config->update_cache; + sync_config->update_cache = 0; + } + spin_unlock_irqrestore(&hw->group_lock, flags); + for (i = 0; i < sync_config->dev_cnt; i++) { + if (sync_config->mode == RKCIF_MASTER_MASTER) { + if (i < sync_config->ext_master.count) + tmp_dev = sync_config->ext_master.cif_dev[i]; + else + tmp_dev = sync_config->int_master.cif_dev[0]; + } else if (sync_config->mode == RKCIF_MASTER_SLAVE) { + if (i < sync_config->slave.count) + tmp_dev = sync_config->slave.cif_dev[i]; + else + tmp_dev = sync_config->int_master.cif_dev[0]; + } else { + v4l2_err(&cif_dev->v4l2_dev, + "ERROR: invalid group sync mode\n"); + } + if (tmp_dev) { + rkcif_send_sof(tmp_dev); + tmp_dev->stream[0].frame_idx = sync_config->frame_idx; + } + } + } + } else { + if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode) { + rkcif_send_sof(cif_dev); + detect_stream->frame_idx++; + } + if (detect_stream->cifdev->rdbk_debug && + detect_stream->frame_idx < 15 && + (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode)) + v4l2_info(&cif_dev->v4l2_dev, + "stream[%d] sof %d %lld\n", + detect_stream->id, + detect_stream->frame_idx - 1, + ktime_get_ns()); + } +} + +unsigned int rkcif_irq_global(struct rkcif_device *cif_dev) +{ + unsigned int intstat_glb = 0; + + intstat_glb = rkcif_read_register(cif_dev, CIF_REG_GLB_INTST); + if (intstat_glb) + v4l2_dbg(2, rkcif_debug, &cif_dev->v4l2_dev, + "intstat_glb 0x%x\n", + intstat_glb); + else + return intstat_glb; + + if (intstat_glb & SCALE_TOISP_AXI0_ERR) { + v4l2_err(&cif_dev->v4l2_dev, + "ERROR: scale channel, AXI0 bus err intstat_glb:0x%x !!\n", + intstat_glb); + return 0; + } + if (intstat_glb & SCALE_TOISP_AXI1_ERR) { + v4l2_err(&cif_dev->v4l2_dev, + "ERROR: scale channel, AXI1 bus err intstat_glb:0x%x !!\n", + intstat_glb); + return 0; + } + rkcif_irq_handle_scale(cif_dev, intstat_glb); + return intstat_glb; +} + +static bool rkcif_check_buffer_prepare(struct rkcif_stream *stream) +{ + struct rkcif_device *cif_dev = stream->cifdev; + unsigned long flags; + bool is_update = false; + struct rkcif_multi_sync_config *sync_config; + + spin_lock_irqsave(&cif_dev->hw_dev->group_lock, flags); + sync_config = &cif_dev->hw_dev->sync_config[cif_dev->sync_cfg.group]; + if (stream->id == 0 && + sync_config->update_code & BIT(cif_dev->csi_host_idx)) { + is_update = true; + sync_config->update_code &= ~(BIT(cif_dev->csi_host_idx)); + if (!sync_config->update_code && + sync_config->update_cache) { + sync_config->update_code = sync_config->update_cache; + sync_config->update_cache = 0; + } + } else { + if (cif_dev->rdbk_buf[RDBK_L]) + is_update = true; + } + + spin_unlock_irqrestore(&cif_dev->hw_dev->group_lock, flags); + return is_update; +} + +void rkcif_err_print_work(struct work_struct *work) +{ + struct rkcif_err_state_work *err_state_work = container_of(work, + struct rkcif_err_state_work, + work); + struct rkcif_device *dev = container_of(err_state_work, + struct rkcif_device, + err_state_work); + u32 err_state = 0; + int intstat = 0; + int lastline = 0; + int lastpixel = 0; + u64 cur_time = 0; + bool is_print = false; + + cur_time = ktime_get_ns(); + if (err_state_work->last_timestamp == 0) { + is_print = true; + } else { + if (cur_time - err_state_work->last_timestamp > 500000000) + is_print = true; + } + err_state_work->last_timestamp = cur_time; + err_state = err_state_work->err_state; + intstat = err_state_work->intstat; + lastline = err_state_work->lastline; + lastpixel = err_state_work->lastpixel; + if (err_state & RKCIF_ERR_ID0_NOT_BUF && is_print) + v4l2_err(&dev->v4l2_dev, + "stream[0] not active buffer, frame num %d, cnt %llu\n", + dev->stream[0].frame_idx, dev->irq_stats.not_active_buf_cnt[0]); + if (err_state & RKCIF_ERR_ID1_NOT_BUF && is_print) + v4l2_err(&dev->v4l2_dev, + "stream[1] not active buffer, frame num %d, cnt %llu\n", + dev->stream[1].frame_idx, dev->irq_stats.not_active_buf_cnt[1]); + if (err_state & RKCIF_ERR_ID2_NOT_BUF && is_print) + v4l2_err(&dev->v4l2_dev, + "stream[2] not active buffer, frame num %d, cnt %llu\n", + dev->stream[2].frame_idx, dev->irq_stats.not_active_buf_cnt[2]); + if (err_state & RKCIF_ERR_ID3_NOT_BUF && is_print) + v4l2_err(&dev->v4l2_dev, + "stream[3] not active buffer, frame num %d, cnt %llu\n", + dev->stream[3].frame_idx, dev->irq_stats.not_active_buf_cnt[3]); + if (err_state & RKCIF_ERR_ID0_TRIG_SIMULT && is_print) + v4l2_err(&dev->v4l2_dev, + "stream[0], frm0/frm1 end simultaneously,frm id:%d, cnt %llu\n", + dev->stream[0].frame_idx, dev->irq_stats.trig_simult_cnt[0]); + if (err_state & RKCIF_ERR_ID1_TRIG_SIMULT && is_print) + v4l2_err(&dev->v4l2_dev, + "stream[1], frm0/frm1 end simultaneously,frm id:%d, cnt %llu\n", + dev->stream[1].frame_idx, dev->irq_stats.trig_simult_cnt[1]); + if (err_state & RKCIF_ERR_ID2_TRIG_SIMULT && is_print) + v4l2_err(&dev->v4l2_dev, + "stream[2], frm0/frm1 end simultaneously,frm id:%d, cnt %llu\n", + dev->stream[2].frame_idx, dev->irq_stats.trig_simult_cnt[2]); + if (err_state & RKCIF_ERR_ID3_TRIG_SIMULT && is_print) + v4l2_err(&dev->v4l2_dev, + "stream[3], frm0/frm1 end simultaneously,frm id:%d, cnt %llu\n", + dev->stream[3].frame_idx, dev->irq_stats.trig_simult_cnt[3]); + if (err_state & RKCIF_ERR_SIZE) + v4l2_err(&dev->v4l2_dev, + "ERROR: csi size err, intstat:0x%x, lastline:0x%x, cnt %llu\n", + intstat, lastline, dev->irq_stats.csi_size_err_cnt); + if (err_state & RKCIF_ERR_OVERFLOW) + v4l2_err(&dev->v4l2_dev, + "ERROR: csi fifo overflow, intstat:0x%x, lastline:0x%x, cnt %llu\n", + intstat, lastline, dev->irq_stats.csi_overflow_cnt); + if (err_state & RKCIF_ERR_BANDWIDTH_LACK) + v4l2_err(&dev->v4l2_dev, + "ERROR: csi bandwidth lack, intstat:0x%x, lastline:0x%x, cnt %llu\n", + intstat, lastline, dev->irq_stats.csi_bwidth_lack_cnt); + if (err_state & RKCIF_ERR_ID0_MULTI_FS) + v4l2_err(&dev->v4l2_dev, + "ERR: multi fs in oneframe in id0, fs_num:%u\n", + dev->stream[0].fs_cnt_in_single_frame); + if (err_state & RKCIF_ERR_BUS) + v4l2_err(&dev->v4l2_dev, "dvp bus err, intstat 0x%x, last line 0x%x\n", + intstat, lastline); + if (err_state & RKCIF_ERR_PIXEL) + v4l2_err(&dev->v4l2_dev, "dvp pix err, intstat 0x%x, last pixel 0x%x\n", + intstat, lastpixel); + if (err_state & RKCIF_ERR_LINE) + v4l2_err(&dev->v4l2_dev, "dvp line err, intstat 0x%x, last line 0x%x\n", + intstat, lastline); +} + +/* pingpong irq for rk3588 and next */ +void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) +{ + struct rkcif_stream *stream; + struct rkcif_stream *detect_stream = &cif_dev->stream[0]; + struct v4l2_mbus_config *mbus; + unsigned int intstat, i = 0xff; + unsigned long flags; + bool is_update = false; + int ret = 0; + + if (!cif_dev->active_sensor) + return; + + mbus = &cif_dev->active_sensor->mbus; + if (mbus->type == V4L2_MBUS_CSI2_DPHY || + mbus->type == V4L2_MBUS_CSI2_CPHY || + mbus->type == V4L2_MBUS_CCP2) { + int mipi_id; + u32 lastline = 0; + + intstat = rkcif_read_register(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT); + lastline = rkcif_read_register(cif_dev, CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1); + cif_dev->err_state_work.lastline = lastline; + cif_dev->err_state_work.intstat = intstat; + + /* clear all interrupts that has been triggered */ + if (intstat) { + rkcif_write_register(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT, intstat); + v4l2_dbg(2, rkcif_debug, &cif_dev->v4l2_dev, + "intstat 0x%x\n", + intstat); + } else { + return; + } + + if (intstat & CSI_SIZE_ERR) { + cif_dev->irq_stats.csi_size_err_cnt++; + cif_dev->err_state |= RKCIF_ERR_SIZE; + rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_CTRL, 0x000A0000); + return; + } + + if (intstat & CSI_FIFO_OVERFLOW_V1) { + cif_dev->irq_stats.csi_overflow_cnt++; + cif_dev->err_state |= RKCIF_ERR_OVERFLOW; + return; + } + + if (intstat & CSI_BANDWIDTH_LACK_V1) { + cif_dev->irq_stats.csi_bwidth_lack_cnt++; + cif_dev->err_state |= RKCIF_ERR_BANDWIDTH_LACK; + } + + if (intstat & CSI_ALL_ERROR_INTEN_V1) { + cif_dev->irq_stats.all_err_cnt++; + return; + } + + for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { + mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev, + intstat); + if (mipi_id < 0) + continue; + + stream = &cif_dev->stream[mipi_id]; + if (!cif_dev->sditf[0] || + cif_dev->sditf[0]->mode.rdbk_mode) + stream->buf_wake_up_cnt++; + + if (stream->stopping && (!stream->dma_en)) { + rkcif_stream_stop(stream); + stream->stopping = false; + wake_up(&stream->wq_stopped); + continue; + } + + if (stream->state != RKCIF_STATE_STREAMING) + continue; + stream->is_in_vblank = true; + switch (mipi_id) { + case RKCIF_STREAM_MIPI_ID0: + stream->frame_phase = SW_FRM_END_ID0(intstat); + intstat &= ~CSI_FRAME_END_ID0; + break; + case RKCIF_STREAM_MIPI_ID1: + stream->frame_phase = SW_FRM_END_ID1(intstat); + intstat &= ~CSI_FRAME_END_ID1; + break; + case RKCIF_STREAM_MIPI_ID2: + stream->frame_phase = SW_FRM_END_ID2(intstat); + intstat &= ~CSI_FRAME_END_ID2; + break; + case RKCIF_STREAM_MIPI_ID3: + stream->frame_phase = SW_FRM_END_ID3(intstat); + intstat &= ~CSI_FRAME_END_ID3; + break; + } + if (stream->cifdev->rdbk_debug && + stream->frame_idx < 15 && + (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode)) + v4l2_info(&cif_dev->v4l2_dev, + "stream[%d] fe %d, phase %d, %lld\n", + stream->id, + stream->frame_idx - 1, + stream->frame_phase, + ktime_get_ns()); + if (stream->is_finish_stop_dma && stream->is_wait_dma_stop) { + stream->is_wait_dma_stop = false; + wake_up(&stream->wq_stopped); + stream->is_finish_stop_dma = false; + continue; + } + if (stream->crop_dyn_en) + rkcif_dynamic_crop(stream); + + if (stream->dma_en & RKCIF_DMAEN_BY_VICAP) { + if (cif_dev->sync_cfg.type == RKCIF_NOSYNC_MODE) + is_update = true; + else + is_update = rkcif_check_buffer_prepare(stream); + v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev, + "dma capture by vicap, is_updata %d, group mode %d, dma_en %d\n", + is_update, cif_dev->sync_cfg.type, stream->dma_en); + if (is_update) + rkcif_update_stream(cif_dev, stream, mipi_id); + } else if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { + v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev, + "dma capture by isp, dma_en 0x%x\n", + stream->dma_en); + rkcif_update_stream_toisp(cif_dev, stream, mipi_id); + } else if (stream->dma_en & RKCIF_DMAEN_BY_ROCKIT) { + v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev, + "dma capture by rockit, dma_en 0x%x\n", + stream->dma_en); + rkcif_update_stream_rockit(cif_dev, stream, mipi_id); + } + + if (cif_dev->chip_id >= CHIP_RV1106_CIF) + rkcif_modify_frame_skip_config(stream); + if (stream->is_change_toisp) { + stream->is_change_toisp = false; + if ((cif_dev->hdr.hdr_mode == HDR_X2 && stream->id != 1) || + (cif_dev->hdr.hdr_mode == HDR_X3 && stream->id != 2)) + rkcif_release_unnecessary_buf_for_online(stream, + stream->curr_buf_toisp); + else + sditf_change_to_online(cif_dev->sditf[0]); + } + + spin_lock_irqsave(&stream->vbq_lock, flags); + if (!(stream->dma_en & RKCIF_DMAEN_BY_ISP) && stream->lack_buf_cnt == 2) { + v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev, + "stream[%d] to stop dma, lack_buf_cnt %d\n", + stream->id, stream->lack_buf_cnt); + stream->to_stop_dma = RKCIF_DMAEN_BY_VICAP; + rkcif_stop_dma_capture(stream); + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); + if (stream->to_en_scale) { + stream->to_en_scale = false; + rkcif_scale_start(stream->scale_vdev); + } + rkcif_detect_wake_up_mode_change(stream); + if (cif_dev->chip_id < CHIP_RK3588_CIF && + mipi_id == RKCIF_STREAM_MIPI_ID0) { + if ((intstat & (CSI_FRAME1_START_ID0 | CSI_FRAME0_START_ID0)) == 0 && + detect_stream->fs_cnt_in_single_frame > 1) { + cif_dev->err_state |= RKCIF_ERR_ID0_MULTI_FS; + detect_stream->is_fs_fe_not_paired = true; + detect_stream->fs_cnt_in_single_frame = 0; + } else { + detect_stream->fs_cnt_in_single_frame--; + } + } + rkcif_monitor_reset_event(cif_dev); + cif_dev->irq_stats.frm_end_cnt[stream->id]++; + } + + for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { + if (intstat & CSI_START_INTSTAT(i)) { + stream = &cif_dev->stream[i]; + if (i == 0) { + rkcif_deal_sof(cif_dev); + } else { + spin_lock_irqsave(&stream->fps_lock, flags); + stream->readout.fs_timestamp = ktime_get_ns(); + stream->frame_idx++; + spin_unlock_irqrestore(&stream->fps_lock, flags); + } + stream->is_in_vblank = false; + spin_lock_irqsave(&stream->vbq_lock, flags); + if (stream->stopping && stream->dma_en) { + if (stream->dma_en & RKCIF_DMAEN_BY_VICAP) + stream->to_stop_dma = RKCIF_DMAEN_BY_VICAP; + else if (stream->dma_en & RKCIF_DMAEN_BY_ISP) + stream->to_stop_dma = RKCIF_DMAEN_BY_ISP; + stream->is_stop_capture = true; + } + if (stream->to_stop_dma) { + ret = rkcif_stop_dma_capture(stream); + if (!ret) + stream->is_finish_stop_dma = true; + } + if (stream->to_en_dma) + rkcif_enable_dma_capture(stream, false); + spin_unlock_irqrestore(&stream->vbq_lock, flags); + } + if (intstat & CSI_LINE_INTSTAT_V1(i)) { + stream = &cif_dev->stream[i]; + if (stream->is_line_inten) { + stream->line_int_cnt++; + if (cif_dev->rdbk_debug > 1 && + stream->frame_idx < 15) + v4l2_info(&cif_dev->v4l2_dev, + "line int %lld\n", + stream->line_int_cnt); + if (cif_dev->sditf[0] && cif_dev->sditf[0]->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) + rkcif_line_wake_up_rdbk(stream, stream->id); + else + rkcif_line_wake_up(stream, stream->id); + rkcif_modify_line_int(stream, false); + stream->is_line_inten = false; + } + v4l2_dbg(3, rkcif_debug, &cif_dev->v4l2_dev, + "%s: id0 cur line:%d\n", __func__, lastline & 0x3fff); + } + } + } else { + struct rkcif_stream *stream; + int ch_id; + int lastline; + + intstat = rkcif_read_register(cif_dev, CIF_REG_DVP_INTSTAT); + if (intstat) + rkcif_write_register(cif_dev, CIF_REG_DVP_INTSTAT, intstat); + else + return; + lastline = rkcif_read_register(cif_dev, CIF_REG_DVP_LINE_CNT); + cif_dev->err_state_work.lastline = lastline; + cif_dev->err_state_work.intstat = intstat; + stream = &cif_dev->stream[RKCIF_STREAM_CIF]; + + if (intstat & DVP_SIZE_ERR) { + cif_dev->irq_stats.dvp_size_err_cnt++; + rkcif_write_register_or(cif_dev, CIF_REG_DVP_CTRL, 0x000A0000); + cif_dev->err_state |= RKCIF_ERR_SIZE; + } + + if (intstat & DVP_FIFO_OVERFLOW) { + cif_dev->irq_stats.dvp_overflow_cnt++; + cif_dev->err_state |= RKCIF_ERR_OVERFLOW; + } + + if (intstat & DVP_BANDWIDTH_LACK) { + cif_dev->irq_stats.dvp_bwidth_lack_cnt++; + cif_dev->err_state |= RKCIF_ERR_BANDWIDTH_LACK; + } + + if (intstat & INTSTAT_ERR_RK3588) { + cif_dev->irq_stats.all_err_cnt++; + } + + for (i = 0; i < RKCIF_MAX_STREAM_DVP; i++) { + ch_id = rkcif_dvp_g_ch_id_by_fe(&cif_dev->v4l2_dev, intstat); + + if (ch_id < 0) + continue; + + stream = &cif_dev->stream[ch_id]; + if (!cif_dev->sditf[0] || + cif_dev->sditf[0]->mode.rdbk_mode) + stream->buf_wake_up_cnt++; + + if (stream->stopping) { + rkcif_stream_stop(stream); + stream->stopping = false; + wake_up(&stream->wq_stopped); + continue; + } + + if (stream->state != RKCIF_STATE_STREAMING) + continue; + stream->is_in_vblank = true; + switch (ch_id) { + case RKCIF_STREAM_MIPI_ID0: + stream->frame_phase = SW_FRM_END_ID0(intstat); + intstat &= ~DVP_ALL_END_ID0; + break; + case RKCIF_STREAM_MIPI_ID1: + stream->frame_phase = SW_FRM_END_ID1(intstat); + intstat &= ~DVP_ALL_END_ID1; + break; + case RKCIF_STREAM_MIPI_ID2: + stream->frame_phase = SW_FRM_END_ID2(intstat); + intstat &= ~DVP_ALL_END_ID2; + break; + case RKCIF_STREAM_MIPI_ID3: + stream->frame_phase = SW_FRM_END_ID3(intstat); + intstat &= ~DVP_ALL_END_ID3; + break; + } + if (stream->dma_en & RKCIF_DMAEN_BY_VICAP) { + if (cif_dev->sync_cfg.type == RKCIF_NOSYNC_MODE) + is_update = true; + else + is_update = rkcif_check_buffer_prepare(stream); + if (is_update) + rkcif_update_stream(cif_dev, stream, ch_id); + } else if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { + rkcif_update_stream_toisp(cif_dev, stream, ch_id); + } else if (stream->dma_en & RKCIF_DMAEN_BY_ROCKIT) { + rkcif_update_stream_rockit(cif_dev, stream, ch_id); + } + + if (stream->to_en_dma) + rkcif_enable_dma_capture(stream, false); + if (stream->to_stop_dma) { + rkcif_stop_dma_capture(stream); + wake_up(&stream->wq_stopped); + } + cif_dev->irq_stats.frm_end_cnt[stream->id]++; + } + + if (intstat & DVP_FRAME0_START_ID0 || intstat & DVP_FRAME1_START_ID0) { + stream->is_in_vblank = false; + rkcif_deal_sof(cif_dev); + } + + if (stream->crop_dyn_en) + rkcif_dynamic_crop(stream); + } +} + void rkcif_irq_pingpong(struct rkcif_device *cif_dev) { struct rkcif_stream *stream; struct rkcif_stream *detect_stream = &cif_dev->stream[0]; struct v4l2_mbus_config *mbus; - unsigned int intstat = 0x0, i = 0xff, bak_intstat = 0x0; + unsigned int intstat = 0x0, i = 0xff; unsigned long flags; int ret = 0; @@ -6099,7 +10686,8 @@ return; mbus = &cif_dev->active_sensor->mbus; - if ((mbus->type == V4L2_MBUS_CSI2 || + if ((mbus->type == V4L2_MBUS_CSI2_DPHY || + mbus->type == V4L2_MBUS_CSI2_CPHY || mbus->type == V4L2_MBUS_CCP2) && (cif_dev->chip_id == CHIP_RK1808_CIF || cif_dev->chip_id == CHIP_RV1126_CIF || @@ -6109,51 +10697,26 @@ intstat = rkcif_read_register(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT); lastline = rkcif_read_register(cif_dev, CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1); + cif_dev->err_state_work.lastline = lastline; + cif_dev->err_state_work.intstat = intstat; /* clear all interrupts that has been triggered */ rkcif_write_register(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT, intstat); if (intstat & CSI_FIFO_OVERFLOW) { cif_dev->irq_stats.csi_overflow_cnt++; - v4l2_err(&cif_dev->v4l2_dev, - "ERROR: csi fifo overflow, intstat:0x%x, lastline:%d!!\n", - intstat, lastline); - return; + cif_dev->err_state |= RKCIF_ERR_OVERFLOW; } if (intstat & CSI_BANDWIDTH_LACK) { cif_dev->irq_stats.csi_bwidth_lack_cnt++; - v4l2_err(&cif_dev->v4l2_dev, - "ERROR: csi bandwidth lack, intstat:0x%x!!\n", - intstat); + cif_dev->err_state |= RKCIF_ERR_BANDWIDTH_LACK; return; } if (intstat & CSI_ALL_ERROR_INTEN) { cif_dev->irq_stats.all_err_cnt++; - v4l2_err(&cif_dev->v4l2_dev, - "ERROR: CSI_ALL_ERROR_INTEN:0x%x!!\n", intstat); return; - } - - if ((intstat & (CSI_FRAME0_START_ID0 | CSI_FRAME1_START_ID0)) == - (CSI_FRAME0_START_ID0 | CSI_FRAME1_START_ID0)) { - v4l2_err(&cif_dev->v4l2_dev, "%s:ERR: double fs in one fs int\n", - __func__); - } - - for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { - if (intstat & CSI_LINE_INTSTAT(i)) { - stream = &cif_dev->stream[i]; - if (stream->is_line_inten) { - stream->line_int_cnt++; - rkcif_line_wake_up(stream, stream->id); - rkcif_modify_line_int(stream, false); - stream->is_line_inten = false; - } - v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, - "%s: id0 cur line:%d\n", __func__, lastline & 0x3fff); - } } for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { @@ -6197,42 +10760,44 @@ rkcif_update_stream(cif_dev, stream, mipi_id); rkcif_detect_wake_up_mode_change(stream); + rkcif_monitor_reset_event(cif_dev); if (mipi_id == RKCIF_STREAM_MIPI_ID0) { if ((intstat & (CSI_FRAME1_START_ID0 | CSI_FRAME0_START_ID0)) == 0 && detect_stream->fs_cnt_in_single_frame > 1) { - v4l2_dbg(2, rkcif_debug, &cif_dev->v4l2_dev, - "%s ERR: multi fs in oneframe, bak_int:0x%x, fs_num:%u\n", - __func__, - bak_intstat, - detect_stream->fs_cnt_in_single_frame); + cif_dev->err_state |= RKCIF_ERR_ID0_MULTI_FS; detect_stream->is_fs_fe_not_paired = true; detect_stream->fs_cnt_in_single_frame = 0; } else { detect_stream->fs_cnt_in_single_frame--; } } - cif_dev->irq_stats.all_frm_end_cnt++; + cif_dev->irq_stats.frm_end_cnt[stream->id]++; } for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { if (intstat & CSI_START_INTSTAT(i)) { stream = &cif_dev->stream[i]; if (i == 0) { - if (mbus->type == V4L2_MBUS_CSI2) - rkcif_csi2_event_inc_sof(); - else if (mbus->type == V4L2_MBUS_CCP2) - rkcif_lvds_event_inc_sof(cif_dev); - stream->fs_cnt_in_single_frame++; - spin_lock_irqsave(&stream->fps_lock, flags); - stream->readout.fs_timestamp = ktime_get_ns(); - spin_unlock_irqrestore(&stream->fps_lock, flags); + rkcif_deal_sof(cif_dev); } else { spin_lock_irqsave(&stream->fps_lock, flags); stream->readout.fs_timestamp = ktime_get_ns(); + stream->frame_idx++; spin_unlock_irqrestore(&stream->fps_lock, flags); } + stream->is_in_vblank = false; + } + if (intstat & CSI_LINE_INTSTAT(i)) { + stream = &cif_dev->stream[i]; + if (stream->is_line_inten) { + stream->line_int_cnt++; + rkcif_line_wake_up(stream, stream->id); + rkcif_modify_line_int(stream, false); + stream->is_line_inten = false; + } + v4l2_dbg(3, rkcif_debug, &cif_dev->v4l2_dev, + "%s: id0 cur line:%d\n", __func__, lastline & 0x3fff); } } - } else { u32 lastline, lastpix, ctl; u32 cif_frmst, frmid, int_en; @@ -6246,49 +10811,36 @@ lastpix = rkcif_read_register(cif_dev, CIF_REG_DVP_LAST_PIX); lastpix = CIF_FETCH_Y_LAST_LINE(lastpix); ctl = rkcif_read_register(cif_dev, CIF_REG_DVP_CTRL); + cif_dev->err_state_work.lastline = lastline; + cif_dev->err_state_work.lastpixel = lastpix; + cif_dev->err_state_work.intstat = intstat; rkcif_write_register(cif_dev, CIF_REG_DVP_INTSTAT, intstat); stream = &cif_dev->stream[RKCIF_STREAM_CIF]; - if ((intstat & LINE_INT_END) && !(intstat & FRAME_END) && - (cif_dev->dvp_sof_in_oneframe == 0)) { - if ((intstat & (PRE_INF_FRAME_END | PST_INF_FRAME_END)) == 0x0) { - if ((intstat & INTSTAT_ERR) == 0x0) { - rkcif_dvp_event_inc_sof(cif_dev); - int_en = rkcif_read_register(cif_dev, CIF_REG_DVP_INTEN); - int_en &= ~LINE_INT_EN; - rkcif_write_register(cif_dev, CIF_REG_DVP_INTEN, int_en); - cif_dev->dvp_sof_in_oneframe = 1; - } - } - } - if (intstat & BUS_ERR) { cif_dev->irq_stats.dvp_bus_err_cnt++; - v4l2_info(&cif_dev->v4l2_dev, "dvp bus err\n"); + cif_dev->err_state |= RKCIF_ERR_BUS; } if (intstat & DVP_ALL_OVERFLOW) { cif_dev->irq_stats.dvp_overflow_cnt++; - v4l2_info(&cif_dev->v4l2_dev, "dvp overflow err\n"); + cif_dev->err_state |= RKCIF_ERR_OVERFLOW; } if (intstat & LINE_ERR) { cif_dev->irq_stats.dvp_line_err_cnt++; - v4l2_info(&cif_dev->v4l2_dev, "dvp line err\n"); + cif_dev->err_state |= RKCIF_ERR_LINE; } if (intstat & PIX_ERR) { cif_dev->irq_stats.dvp_pix_err_cnt++; - v4l2_info(&cif_dev->v4l2_dev, "dvp pix err\n"); + cif_dev->err_state |= RKCIF_ERR_PIXEL; } - if (intstat & INTSTAT_ERR) { + if (intstat & INTSTAT_ERR) cif_dev->irq_stats.all_err_cnt++; - v4l2_err(&cif_dev->v4l2_dev, - "ERROR: DVP_ALL_ERROR_INTEN:0x%x!!\n", intstat); - } /* There are two irqs enabled: * - PST_INF_FRAME_END: cif FIFO is ready, @@ -6309,7 +10861,7 @@ stream = &cif_dev->stream[RKCIF_STREAM_CIF]; if ((intstat & FRAME_END)) { - struct vb2_v4l2_buffer *vb_done = NULL; + struct rkcif_buffer *active_buf = NULL; int_en = rkcif_read_register(cif_dev, CIF_REG_DVP_INTEN); int_en |= LINE_INT_EN; @@ -6329,7 +10881,7 @@ v4l2_info(&cif_dev->v4l2_dev, "frmid:%d, frmstat:0x%x\n", frmid, cif_frmst); rkcif_write_register(cif_dev, CIF_REG_DVP_FRAME_STATUS, - cif_frmst & 0x3); + FRAME_STAT_CLS); } if (lastline != stream->pixm.height || @@ -6345,11 +10897,11 @@ if (cif_frmst & CIF_F0_READY) { if (stream->curr_buf) - vb_done = &stream->curr_buf->vb; + active_buf = stream->curr_buf; stream->frame_phase = CIF_CSI_FRAME0_READY; } else if (cif_frmst & CIF_F1_READY) { if (stream->next_buf) - vb_done = &stream->next_buf->vb; + active_buf = stream->next_buf; stream->frame_phase = CIF_CSI_FRAME1_READY; } @@ -6363,12 +10915,12 @@ ret = rkcif_assign_new_buffer_oneframe(stream, RKCIF_YUV_ADDR_STATE_UPDATE); - if (vb_done && (!ret)) { - vb_done->sequence = stream->frame_idx; - rkcif_vb_done_oneframe(stream, vb_done); + if (active_buf && (!ret)) { + active_buf->vb.sequence = stream->frame_idx; + rkcif_vb_done_tasklet(stream, active_buf); } stream->frame_idx++; - cif_dev->irq_stats.all_frm_end_cnt++; + cif_dev->irq_stats.frm_end_cnt[stream->id]++; } } else { for (i = 0; i < RKCIF_MAX_STREAM_DVP; i++) { @@ -6417,10 +10969,23 @@ v4l2_info(&cif_dev->v4l2_dev, "frmid:%d, frmstat:0x%x\n", frmid, cif_frmst); rkcif_write_register(cif_dev, CIF_REG_DVP_FRAME_STATUS, - cif_frmst & 0xffff); + FRAME_STAT_CLS); } rkcif_update_stream(cif_dev, stream, ch_id); - cif_dev->irq_stats.all_frm_end_cnt++; + cif_dev->irq_stats.frm_end_cnt[stream->id]++; + } + } + + if ((intstat & LINE_INT_END) && !(intstat & FRAME_END) && + (cif_dev->dvp_sof_in_oneframe == 0)) { + if ((intstat & (PRE_INF_FRAME_END | PST_INF_FRAME_END)) == 0x0) { + if ((intstat & INTSTAT_ERR) == 0x0) { + rkcif_deal_sof(cif_dev); + int_en = rkcif_read_register(cif_dev, CIF_REG_DVP_INTEN); + int_en &= ~LINE_INT_EN; + rkcif_write_register(cif_dev, CIF_REG_DVP_INTEN, int_en); + cif_dev->dvp_sof_in_oneframe = 1; + } } } @@ -6442,6 +11007,8 @@ intstat = rkcif_read_register(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT); lastline = rkcif_read_register(cif_dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1); + cif_dev->err_state_work.lastline = lastline; + cif_dev->err_state_work.intstat = intstat; /* clear all interrupts that has been triggered */ rkcif_write_register(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT, intstat); @@ -6465,18 +11032,6 @@ "ERROR: cif lite lvds all err:0x%x!!\n", intstat); return; } - - if (intstat & CSI_FRAME0_START_ID0) - rkcif_lvds_event_inc_sof(cif_dev); - - - if (intstat & CSI_FRAME1_START_ID0) - rkcif_lvds_event_inc_sof(cif_dev); - - /* if do not reach frame dma end, return irq */ - mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev, intstat); - if (mipi_id < 0) - return; for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev, @@ -6516,7 +11071,31 @@ } rkcif_update_stream(cif_dev, stream, mipi_id); + rkcif_monitor_reset_event(cif_dev); + cif_dev->irq_stats.frm_end_cnt[stream->id]++; } - cif_dev->irq_stats.all_frm_end_cnt++; + + if (intstat & CSI_FRAME0_START_ID0) + rkcif_lvds_event_inc_sof(cif_dev); + + if (intstat & CSI_FRAME1_START_ID0) + rkcif_lvds_event_inc_sof(cif_dev); } } + +int rkcif_sditf_disconnect(struct video_device *vdev) +{ + struct rkcif_vdev_node *vnode = vdev_to_node(vdev); + struct rkcif_stream *stream = to_rkcif_stream(vnode); + struct rkcif_device *cifdev = stream->cifdev; + struct media_link *link; + int ret; + + link = list_first_entry(&cifdev->sditf[0]->sd.entity.links, struct media_link, list); + ret = media_entity_setup_link(link, 0); + if (ret) + dev_err(cifdev->dev, "failed to disable link of sditf with isp"); + + return ret; +} +EXPORT_SYMBOL(rkcif_sditf_disconnect); -- Gitblit v1.6.2