diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index ab66e49ede13..a27cc872b529 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -351,6 +351,7 @@ static const struct cif_output_fmt out_fmts[] = { .mplanes = 1, .bpp = { 16 }, .raw_bpp = 16, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW16, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SGRBG16, @@ -358,6 +359,7 @@ static const struct cif_output_fmt out_fmts[] = { .mplanes = 1, .bpp = { 16 }, .raw_bpp = 16, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW16, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SGBRG16, @@ -365,6 +367,7 @@ static const struct cif_output_fmt out_fmts[] = { .mplanes = 1, .bpp = { 16 }, .raw_bpp = 16, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW16, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SBGGR16, @@ -372,6 +375,7 @@ static const struct cif_output_fmt out_fmts[] = { .mplanes = 1, .bpp = { 16 }, .raw_bpp = 16, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW16, .fmt_type = CIF_FMT_TYPE_RAW, } /* TODO: We can support NV12M/NV21M/NV16M/NV61M too */ @@ -506,6 +510,26 @@ static const struct cif_input_fmt in_fmts[] = { .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR14_1X14, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW14_RK3588, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG14_1X14, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW14_RK3588, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG14_1X14, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW14_RK3588, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB14_1X14, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW14_RK3588, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, .csi_fmt_val = CSI_WRDDR_TYPE_RGB888, @@ -552,7 +576,37 @@ static const struct cif_input_fmt in_fmts[] = { .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, - } + }, { + .mbus_code = MEDIA_BUS_FMT_YUV8_1X24,//use for yuv420_8bit input + .csi_fmt_val = CSI_WRDDR_TYPE_YUV420SP, + .fmt_type = CIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_UV8_1X8,//use for yuv420_8bit legacy input + .csi_fmt_val = CSI_WRDDR_TYPE_YUV420LEGACY, + .fmt_type = CIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR16_1X16, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW16, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG16_1X16, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW16, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG16_1X16, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW16, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB16_1X16, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW16, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, }; static inline int rkcif_get_interlace_mode(struct rkcif_stream *stream) @@ -685,6 +739,16 @@ static int rkcif_output_fmt_check(struct rkcif_stream *stream, output_fmt->fourcc == V4L2_PIX_FMT_SBGGR16))) ret = 0; break; + case MEDIA_BUS_FMT_SBGGR16_1X16: + case MEDIA_BUS_FMT_SGBRG16_1X16: + case MEDIA_BUS_FMT_SGRBG16_1X16: + case MEDIA_BUS_FMT_SRGGB16_1X16: + if (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; } @@ -811,6 +875,12 @@ static unsigned char get_data_type(u32 pixelformat, u8 cmd_mode_en, u8 dsi_input case MEDIA_BUS_FMT_SRGGB12_1X12: case MEDIA_BUS_FMT_Y12_1X12: return 0x2c; + /* csi raw16 */ + case MEDIA_BUS_FMT_SBGGR16_1X16: + case MEDIA_BUS_FMT_SGBRG16_1X16: + case MEDIA_BUS_FMT_SGRBG16_1X16: + case MEDIA_BUS_FMT_SRGGB16_1X16: + return 0x2e; /* csi uyvy 422 */ case MEDIA_BUS_FMT_UYVY8_2X8: case MEDIA_BUS_FMT_VYUY8_2X8: @@ -1682,9 +1752,16 @@ static void rkcif_enable_skip_frame(struct rkcif_stream *stream, int cap_m, int 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); + if (dev->chip_id > CHIP_RK3562_CIF) { + val &= 0xc00fffff; + val |= cap_m << RKCIF_CAP_SHIFT_RK3576 | skip_n << RKCIF_SKIP_SHIFT_RK3576; + } else { + val &= 0xffff00ff; + 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); + if (dev->chip_id > CHIP_RK3562_CIF) + rkcif_write_register_or(dev, get_reg_index_of_id_ctrl0(stream->id), RKCIF_SKIP_EN_RK3576); stream->skip_info.skip_en = true; } @@ -1692,9 +1769,14 @@ 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); + if (dev->chip_id > CHIP_RK3562_CIF) { + rkcif_write_register_and(dev, get_reg_index_of_id_ctrl0(stream->id), + ~RKCIF_SKIP_EN_RK3576); + } else { + 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; } @@ -3492,6 +3574,8 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, channel->virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8); } } + if (dev->chip_id > CHIP_RK3562_CIF && stream->sw_dbg_en) + channel->virtual_width = (channel->virtual_width + 23) / 24 * 24; if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888 || channel->fmt_val == CSI_WRDDR_TYPE_RGB565) channel->width = channel->width * fmt->bpp[0] / 8; @@ -3831,6 +3915,76 @@ static int rkcif_csi_get_output_type_mask(struct rkcif_stream *stream) return mask; } +static int rkcif_csi_get_output_type_mask_rk3576(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 << 3 | CSI_YUV_OUTPUT_ORDER_UYVY >> 4; + break; + case V4L2_PIX_FMT_NV61: + mask = CSI_WRDDR_TYPE_YUV422SP_RK3588 << 3 | CSI_YUV_OUTPUT_ORDER_VYUY >> 4; + break; + case V4L2_PIX_FMT_NV12: + mask = CSI_WRDDR_TYPE_YUV420SP_RK3588 << 3 | CSI_YUV_OUTPUT_ORDER_UYVY >> 4; + break; + case V4L2_PIX_FMT_NV21: + mask = CSI_WRDDR_TYPE_YUV420SP_RK3588 << 3 | CSI_YUV_OUTPUT_ORDER_VYUY >> 4; + break; + case V4L2_PIX_FMT_YUYV: + mask = CSI_WRDDR_TYPE_YUV_PACKET << 3 | CSI_YUV_OUTPUT_ORDER_YUYV >> 4; + break; + case V4L2_PIX_FMT_YVYU: + mask = CSI_WRDDR_TYPE_YUV_PACKET << 3 | CSI_YUV_OUTPUT_ORDER_YVYU >> 4; + break; + case V4L2_PIX_FMT_UYVY: + mask = CSI_WRDDR_TYPE_YUV_PACKET << 3 | CSI_YUV_OUTPUT_ORDER_UYVY >> 4; + break; + case V4L2_PIX_FMT_VYUY: + mask = CSI_WRDDR_TYPE_YUV_PACKET << 3 | CSI_YUV_OUTPUT_ORDER_VYUY >> 4; + 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 << 3; + 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 << 3; + else + mask = CSI_WRDDR_TYPE_RAW_UNCOMPACT << 3; + 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 << 3; + break; + default: + mask = CSI_WRDDR_TYPE_RAW_COMPACT << 3; + break; + } + return mask; +} + static int rkcif_lvds_get_output_type_mask(struct rkcif_stream *stream) { unsigned int mask; @@ -3929,6 +4083,47 @@ static void rkcif_modify_frame_skip_config(struct rkcif_stream *stream) } } +static u32 rkcif_get_parse_type_rk3576(const struct cif_input_fmt *cif_fmt_in) +{ + u32 parse_type = 0; + + switch (cif_fmt_in->csi_fmt_val) { + case CSI_WRDDR_TYPE_RAW8: + parse_type = CSI_WRDDR_TYPE_RAW8 << 3; + break; + case CSI_WRDDR_TYPE_RAW10: + parse_type = CSI_WRDDR_TYPE_RAW10 << 3; + break; + case CSI_WRDDR_TYPE_RAW12: + parse_type = CSI_WRDDR_TYPE_RAW12 << 3; + break; + case CSI_WRDDR_TYPE_RAW14_RK3588: + parse_type = CSI_WRDDR_TYPE_RAW14_RK3588 << 4; + break; + case CSI_WRDDR_TYPE_RGB888: + parse_type = CSI_WRDDR_TYPE_RGB888_RK3576; + break; + case CSI_WRDDR_TYPE_YUV422: + if (cif_fmt_in->field == V4L2_FIELD_NONE) + parse_type = CSI_WRDDR_TYPE_YUV422 << 4; + else + parse_type = (CSI_WRDDR_TYPE_YUV422 + 1) << 4; + break; + case CSI_WRDDR_TYPE_YUV420SP: + parse_type = CSI_WRDDR_TYPE_YUV420SP << 4; + break; + case CSI_WRDDR_TYPE_YUV420LEGACY: + parse_type = CSI_WRDDR_TYPE_YUV420LEGACY; + break; + case CSI_WRDDR_TYPE_RAW16: + parse_type = CSI_WRDDR_TYPE_RAW16; + break; + default: + break; + } + return parse_type; +} + /*config reg for rk3588*/ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, struct csi_channel_info *channel, @@ -3953,6 +4148,19 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, return 0; } + if (stream->sw_dbg_en) { + rkcif_write_register_and(dev, CIF_REG_GLB_CTRL, + ~(u32)BIT(16)); + v4l2_subdev_call(dev->active_sensor->sd, + core, ioctl, + RKCIF_CMD_SET_PPI_DATA_DEBUG, + &stream->sw_dbg_en); + } else { + v4l2_subdev_call(dev->active_sensor->sd, + core, ioctl, + RKCIF_CMD_SET_PPI_DATA_DEBUG, + &stream->sw_dbg_en); + } rkcif_write_register_and(dev, CIF_REG_MIPI_LVDS_INTSTAT, ~(CSI_START_INTSTAT(channel->id) | CSI_DMA_END_INTSTAT(channel->id) | @@ -3962,7 +4170,9 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, index < capture_info->multi_dev.dev_num - 1)) { rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, - CSI_START_INTEN(channel->id)); + dev->chip_id < CHIP_RK3576_CIF ? + CSI_START_INTEN(channel->id) : + CSI_START_INTEN_RK3576(channel->id)); if (priv && priv->mode.rdbk_mode && detect_stream->is_line_wake_up) { rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, @@ -3976,28 +4186,39 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, CSI_DMA_END_INTEN(channel->id)); + } + if (stream->cifdev->id_use_cnt == 0) { + if (dev->chip_id > CHIP_RK3562_CIF) { + val = CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE | + (CIF_MIPI_LVDS_SW_WATER_LINE_25 << 19); + if (stream->cifdev->hdr.hdr_mode != NO_HDR && + stream->cifdev->hdr.esp.mode == HDR_NORMAL_VC) + val |= CSI_HDR_VC_MODE_PROTECT >> 25; + val |= (!!stream->sw_dbg_en) << 31; + rkcif_write_register(dev, CIF_REG_MIPI_LVDS_CTRL, val); + } else { + 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); + } 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 || @@ -4005,8 +4226,12 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, (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 (dev->chip_id < CHIP_RK3576_CIF) + rkcif_write_register(dev, get_reg_index_of_id_ctrl1(channel->id), + (channel->width + offset) | (channel->height << 16)); + else + rkcif_write_register(dev, CIF_REG_MIPI_SET_SIZE_ID0 + channel->id, + (channel->width + offset) | (channel->height << 16)); #if IS_ENABLED(CONFIG_CPU_RV1106) if (channel->id == 1) @@ -4050,10 +4275,14 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, if (stream->dma_en) { if (mbus_type == V4L2_MBUS_CSI2_DPHY || - mbus_type == V4L2_MBUS_CSI2_CPHY) - dma_en = CSI_DMA_ENABLE; - else + mbus_type == V4L2_MBUS_CSI2_CPHY) { + if (dev->chip_id > CHIP_RK3562_CIF) + dma_en = CSI_DMA_ENABLE_RK3576; + else + dma_en = CSI_DMA_ENABLE; + } else { dma_en = LVDS_DMAEN_RV1106; + } } if (mbus_type == V4L2_MBUS_CSI2_DPHY || mbus_type == V4L2_MBUS_CSI2_CPHY) { @@ -4062,34 +4291,80 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, 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; + if (dev->chip_id > CHIP_RK3562_CIF) { + val = CSI_ENABLE_CAPTURE | dma_en | + CSI_ENABLE_CROP_RK3576; + val |= rkcif_get_parse_type_rk3576(stream->cif_fmt_in); + val |= rkcif_csi_get_output_type_mask_rk3576(stream); + val |= stream->cif_fmt_in->csi_yuv_order >> 4; + if (stream->is_high_align) + val |= CSI_HIGH_ALIGN_RK3576; + else + val &= ~CSI_HIGH_ALIGN_RK3576; + if (stream->id == 0 && (stream->cif_fmt_out->fourcc == V4L2_PIX_FMT_NV12 || + stream->cif_fmt_out->fourcc == V4L2_PIX_FMT_NV21)) + val |= CSI_UVDS_EN; + rkcif_write_register(dev, get_reg_index_of_id_ctrl0(channel->id), 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); + val = channel->vc | channel->data_type << 2; + + if (stream->cifdev->hdr.hdr_mode == NO_HDR || + stream->cifdev->hdr.hdr_mode == HDR_COMPR) + val |= CSI_NO_HDR >> 12; + else if (stream->cifdev->hdr.hdr_mode == HDR_X2) + val |= CSI_HDR2 >> 12; + else if (stream->cifdev->hdr.hdr_mode == HDR_X3) + val |= CSI_HDR3 >> 12; + if (stream->cifdev->hdr.esp.mode == HDR_NORMAL_VC) { + val |= CSI_HDR_MODE_VC >> 12; + } else if (stream->cifdev->hdr.esp.mode == HDR_LINE_CNT) { + val |= CSI_HDR_MODE_LINE_CNT >> 12; + rkcif_write_register(dev, CIF_REG_MIPI_ON_PAD, 0x4); + val |= stream->id << 12; + } else if (stream->cifdev->hdr.esp.mode == HDR_ID_CODE) { + val |= CSI_HDR_MODE_LINE_INFO >> 12; + } + val |= channel->cmd_mode_en << 14; + rkcif_write_register(dev, get_reg_index_of_id_ctrl1(channel->id), val); + } else { + val = CSI_ENABLE_CAPTURE | dma_en | + channel->cmd_mode_en << 26 | CSI_ENABLE_CROP_V1 | + channel->vc << 8 | channel->data_type << 10; + if (dev->chip_id >= CHIP_RK3588_CIF) { + if (channel->csi_fmt_val == CSI_WRDDR_TYPE_RGB888) + val |= CSI_WRDDR_TYPE_RAW8; + else if (channel->csi_fmt_val == CSI_WRDDR_TYPE_RAW14_RK3588) + val |= channel->csi_fmt_val << 1; + else + val |= channel->csi_fmt_val; + } else { + val |= 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) { @@ -4236,10 +4511,14 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) id = stream->id; val = rkcif_read_register(cif_dev, get_reg_index_of_id_ctrl0(id)); if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || - mbus_cfg->type == V4L2_MBUS_CSI2_CPHY) - val &= ~(CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE); - else + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY) { + if (cif_dev->chip_id >= CHIP_RK3576_CIF) + val &= ~(CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE_RK3576); + else + val &= ~(CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE); + } else { val &= ~LVDS_ENABLE_CAPTURE; + } 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++) { @@ -4613,6 +4892,8 @@ void rkcif_buf_queue(struct vb2_buffer *vb) } if (rkcif_debug && addr && !hw_dev->iommu_en) { memset(addr, 0, pixm->plane_fmt[i].sizeimage); + if (cifbuf->vb.vb2_buf.vb2_queue->mem_ops->finish) + cifbuf->vb.vb2_buf.vb2_queue->mem_ops->finish(cifbuf->vb.vb2_buf.planes[i].mem_priv); v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev, "Clear buffer, size: 0x%08x\n", pixm->plane_fmt[i].sizeimage); @@ -4931,7 +5212,7 @@ static int rkcif_create_dummy_buf(struct rkcif_stream *stream) ret = rkcif_alloc_buffer(dev, dummy_buf); if (ret) { v4l2_err(&dev->v4l2_dev, - "Failed to allocate the memory for dummy buffer\n"); + "Failed to allocate the memory for dummy buffer, size %d\n", max_size); return -ENOMEM; } @@ -5150,13 +5431,17 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, } } } - stream->stopping = true; - ret = wait_event_timeout(stream->wq_stopped, - stream->state != RKCIF_STATE_STREAMING, - msecs_to_jiffies(500)); - if (!ret) { + if (mode == RKCIF_STREAM_MODE_TOSCALE) { rkcif_stream_stop(stream); - stream->stopping = false; + } else { + 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; + } } video_device_pipeline_stop(&node->vdev); @@ -5270,14 +5555,16 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, if (can_reset && hw_dev->dummy_buf.vaddr) rkcif_destroy_dummy_buf(stream); } - if (mode == RKCIF_STREAM_MODE_CAPTURE) + if (mode == RKCIF_STREAM_MODE_CAPTURE) { tasklet_disable(&stream->vb_done_tasklet); + INIT_LIST_HEAD(&stream->vb_done_list); + } 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 (mode == stream->cur_stream_mode) + rkcif_detach_sync_mode(dev); } static void rkcif_stop_streaming(struct vb2_queue *queue) @@ -5417,10 +5704,6 @@ static u32 rkcif_determine_input_mode_rk3588(struct rkcif_stream *stream) break; } } - if (stream->cif_fmt_in->field == V4L2_FIELD_NONE) - mode |= TRANSMIT_PROGRESS_RK3588; - else - mode |= TRANSMIT_INTERFACE_RK3588; return mode; } @@ -5918,10 +6201,26 @@ static int rkcif_stream_start(struct rkcif_stream *stream, unsigned int mode) 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_RK3562_CIF) { + if (sensor_info->mbus.type == V4L2_MBUS_BT656) { + if (stream->cif_fmt_in->field == V4L2_FIELD_NONE) + xfer_mode = BT1120_TRANSMIT_PROGRESS_RK3588; + else + xfer_mode = BT1120_TRANSMIT_INTERFACE_RK3588; + } 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; + } else { + if (sensor_info->mbus.type == V4L2_MBUS_BT656) { + if (stream->cif_fmt_in->field == V4L2_FIELD_NONE) + xfer_mode = BT1120_TRANSMIT_PROGRESS_RK3576; + else + xfer_mode = BT1120_TRANSMIT_INTERFACE_RK3576; + } + 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_RK3576; } if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || @@ -5961,6 +6260,7 @@ static int rkcif_stream_start(struct rkcif_stream *stream, unsigned int mode) | out_fmt_mask | in_fmt_yuv_order | multi_id_en + | xfer_mode | sav_detect | multi_id_sel | multi_id_mode | bt1120_edge_mode; if (stream->is_high_align) @@ -5968,6 +6268,8 @@ static int rkcif_stream_start(struct rkcif_stream *stream, unsigned int mode) else val &= ~CIF_HIGH_ALIGN_RK3588; } + if (dev->chip_id >= CHIP_RK3576_CIF) + val |= DVP_UVDS_EN; rkcif_write_register(dev, CIF_REG_DVP_FOR, val); if (dev->chip_id >= CHIP_RK3588_CIF) { @@ -5995,6 +6297,9 @@ static int rkcif_stream_start(struct rkcif_stream *stream, unsigned int mode) dev->channels[stream->id].crop_en = 0; } + if (dev->chip_id > CHIP_RK3562_CIF && stream->sw_dbg_en) + val = (val + 23) / 24 * 24; + 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 | @@ -6093,6 +6398,16 @@ static int rkcif_stream_start(struct rkcif_stream *stream, unsigned int mode) | DVP_SW_CAP_EN(stream->id) | dma_en | ENABLE_CAPTURE); + } else if (dev->chip_id == CHIP_RK3576_CIF) { + if (stream->dma_en) + dma_en = DVP_SW_DMA_EN_RK3676(stream->id); + if (stream->lack_buf_cnt == 2) + dma_en = 0; + rkcif_write_register(dev, CIF_REG_DVP_CTRL, + DVP_SW_WATER_LINE_25_RK3576 + | DVP_SW_CAP_EN_RK3576(stream->id) + | dma_en + | ENABLE_CAPTURE); } else { rkcif_write_register(dev, CIF_REG_DVP_CTRL, AXI_BURST_16 | workmode | ENABLE_CAPTURE); @@ -6682,6 +6997,8 @@ int rkcif_set_fmt(struct rkcif_stream *stream, bpl = width * bpp / CIF_YUV_STORED_BIT_WIDTH; } } + if (dev->chip_id > CHIP_RK3562_CIF && stream->sw_dbg_en) + bpl = (bpl + 23) / 24 * 24; size = bpl * height; imagesize += size; ex_size = bpl * extend_line->pixm.height; @@ -10165,6 +10482,18 @@ u32 rkcif_mbus_pixelcode_to_v4l2(u32 pixelcode) case MEDIA_BUS_FMT_EBD_1X8: pixelformat = V4l2_PIX_FMT_EBD8; break; + case MEDIA_BUS_FMT_SBGGR16_1X16: + pixelformat = V4L2_PIX_FMT_SBGGR16; + break; + case MEDIA_BUS_FMT_SGBRG16_1X16: + pixelformat = V4L2_PIX_FMT_SGBRG16; + break; + case MEDIA_BUS_FMT_SGRBG16_1X16: + pixelformat = V4L2_PIX_FMT_SGRBG16; + break; + case MEDIA_BUS_FMT_SRGGB16_1X16: + pixelformat = V4L2_PIX_FMT_SRGGB16; + break; default: pixelformat = V4L2_PIX_FMT_SRGGB10; } @@ -10224,6 +10553,7 @@ void rkcif_enable_dma_capture(struct rkcif_stream *stream, bool is_only_enable) struct v4l2_mbus_config *mbus_cfg = &cif_dev->active_sensor->mbus; struct csi_channel_info *channel = &cif_dev->channels[stream->id]; u32 val = 0; + u32 uncompact = 0; if (stream->buf_owner == RKCIF_DMAEN_BY_ISP) stream->buf_owner = RKCIF_DMAEN_BY_ISP_TO_VICAP; @@ -10257,11 +10587,18 @@ void rkcif_enable_dma_capture(struct rkcif_stream *stream, bool is_only_enable) 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; + if (cif_dev->chip_id < CHIP_RK3576_CIF) + uncompact = CSI_WRDDR_TYPE_RAW_UNCOMPACT; else - val &= ~CSI_WRDDR_TYPE_RAW_UNCOMPACT; - val |= CSI_DMA_ENABLE; + uncompact = CSI_WRDDR_TYPE_RAW_UNCOMPACT << 3; + if (!stream->is_compact) + val |= uncompact; + else + val &= ~uncompact; + if (cif_dev->chip_id < CHIP_RK3576_CIF) + val |= CSI_DMA_ENABLE; + else + val |= CSI_DMA_ENABLE_RK3576; 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)); @@ -10310,7 +10647,10 @@ static int rkcif_stop_dma_capture(struct rkcif_stream *stream) 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 (cif_dev->chip_id < CHIP_RK3576_CIF) + val &= ~CSI_DMA_ENABLE; + else + val &= ~CSI_DMA_ENABLE_RK3576; if (stream->is_stop_capture) { val &= ~CSI_ENABLE_CAPTURE; stream->is_stop_capture = false; @@ -10385,6 +10725,30 @@ static int rkcif_g_toisp_fs(unsigned int intstat_glb, int index) return -EINVAL; } +static int rkcif_g_toisp_fs_rk3576(unsigned int intstat_glb, int index) +{ + if (intstat_glb & TOISP_FS_CH0_RK3576(index)) + return RKCIF_TOISP_CH0; + if (intstat_glb & TOISP_FS_CH1_RK3576(index)) + return RKCIF_TOISP_CH1; + if (intstat_glb & TOISP_FS_CH2_RK3576(index)) + return RKCIF_TOISP_CH2; + + return -EINVAL; +} + +static int rkcif_g_toisp_ch_rk3576(unsigned int intstat_glb, int index) +{ + if (intstat_glb & TOISP_END_CH0_RK3576(index)) + return RKCIF_TOISP_CH0; + if (intstat_glb & TOISP_END_CH1_RK3576(index)) + return RKCIF_TOISP_CH1; + if (intstat_glb & TOISP_END_CH2_RK3576(index)) + return RKCIF_TOISP_CH2; + + return -EINVAL; +} + static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, unsigned int intstat_glb, int index) @@ -10398,7 +10762,10 @@ static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, int on = 0; for (i = 0; i < TOISP_CH_MAX; i++) { - ch = rkcif_g_toisp_ch(intstat_glb, index); + if (priv->cif_dev->chip_id < CHIP_RK3576_CIF) + ch = rkcif_g_toisp_ch(intstat_glb, index); + else + ch = rkcif_g_toisp_ch_rk3576(intstat_glb, index); if (ch >= 0) { src_id = priv->toisp_inf.ch_info[ch].id; if (src_id == 24) @@ -10448,22 +10815,34 @@ static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, switch (ch) { case RKCIF_TOISP_CH0: - val = TOISP_END_CH0(index); + if (priv->cif_dev->chip_id < CHIP_RK3576_CIF) + val = TOISP_END_CH0(index); + else + val = TOISP_END_CH0_RK3576(index); intstat_glb = intstat_glb & (~val); break; case RKCIF_TOISP_CH1: - val = TOISP_END_CH1(index); + if (priv->cif_dev->chip_id < CHIP_RK3576_CIF) + val = TOISP_END_CH1(index); + else + val = TOISP_END_CH1_RK3576(index); intstat_glb = intstat_glb & (~val); break; case RKCIF_TOISP_CH2: - val = TOISP_END_CH2(index); + if (priv->cif_dev->chip_id < CHIP_RK3576_CIF) + val = TOISP_END_CH2(index); + else + val = TOISP_END_CH2_RK3576(index); intstat_glb = intstat_glb & (~val); break; default: break; } } - ch = rkcif_g_toisp_fs(intstat_glb, index); + if (priv->cif_dev->chip_id < CHIP_RK3576_CIF) + ch = rkcif_g_toisp_fs(intstat_glb, index); + else + ch = rkcif_g_toisp_fs_rk3576(intstat_glb, index); if (ch >= 0) { src_id = priv->toisp_inf.ch_info[ch].id; if (src_id == 24) @@ -10495,15 +10874,24 @@ static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, } switch (ch) { case RKCIF_TOISP_CH0: - val = TOISP_FS_CH0(index); + if (priv->cif_dev->chip_id < CHIP_RK3576_CIF) + val = TOISP_FS_CH0(index); + else + val = TOISP_FS_CH0_RK3576(index); intstat_glb = intstat_glb & (~val); break; case RKCIF_TOISP_CH1: - val = TOISP_FS_CH1(index); + if (priv->cif_dev->chip_id < CHIP_RK3576_CIF) + val = TOISP_FS_CH1(index); + else + val = TOISP_FS_CH1_RK3576(index); intstat_glb = intstat_glb & (~val); break; case RKCIF_TOISP_CH2: - val = TOISP_FS_CH2(index); + if (priv->cif_dev->chip_id < CHIP_RK3576_CIF) + val = TOISP_FS_CH2(index); + else + val = TOISP_FS_CH2_RK3576(index); intstat_glb = intstat_glb & (~val); break; default: @@ -10674,13 +11062,13 @@ unsigned int rkcif_irq_global(struct rkcif_device *cif_dev) if (intstat_glb & SCALE_TOISP_AXI0_ERR) { v4l2_err(&cif_dev->v4l2_dev, - "ERROR: scale channel, AXI0 bus err intstat_glb:0x%x !!\n", + "ERROR: AXI0 bus err intstat_glb:0x%x !!\n", intstat_glb); return 0; } - if (intstat_glb & SCALE_TOISP_AXI1_ERR) { + if (cif_dev->chip_id != CHIP_RK3576_CIF && intstat_glb & SCALE_TOISP_AXI1_ERR) { v4l2_err(&cif_dev->v4l2_dev, - "ERROR: scale channel, AXI1 bus err intstat_glb:0x%x !!\n", + "ERROR: AXI1 bus err intstat_glb:0x%x !!\n", intstat_glb); return 0; } @@ -11634,7 +12022,8 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) } for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { - if (intstat & CSI_START_INTSTAT(i)) { + if (intstat & (cif_dev->chip_id < CHIP_RK3576_CIF ? + CSI_START_INTSTAT(i) : CSI_START_INTSTAT_RK3576(i))) { stream = &cif_dev->stream[i]; if (i == 0) { if (!stream->cur_skip_frame) diff --git a/drivers/media/platform/rockchip/cif/cif-scale.c b/drivers/media/platform/rockchip/cif/cif-scale.c index a9b97a6e21ad..0be608b2edd7 100644 --- a/drivers/media/platform/rockchip/cif/cif-scale.c +++ b/drivers/media/platform/rockchip/cif/cif-scale.c @@ -56,6 +56,126 @@ static const struct cif_output_fmt scale_out_fmts[] = { .bpp = { 16 }, .raw_bpp = 16, .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .cplanes = 1, + .mplanes = 1, + .bpp = { 8 }, + .raw_bpp = 8, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .cplanes = 1, + .mplanes = 1, + .bpp = { 8 }, + .raw_bpp = 8, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .cplanes = 1, + .mplanes = 1, + .bpp = { 8 }, + .raw_bpp = 8, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .cplanes = 1, + .mplanes = 1, + .bpp = { 8 }, + .raw_bpp = 8, + .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, + .fmt_type = CIF_FMT_TYPE_RAW, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .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_SGRBG10, + .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_SGBRG10, + .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_SBGGR10, + .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_SRGGB12, + .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_SGRBG12, + .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_SGBRG12, + .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_SBGGR12, + .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_GREY, + .cplanes = 1, + .mplanes = 1, + .bpp = {8}, + .raw_bpp = 8, + .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, } }; @@ -88,6 +208,18 @@ static u32 rkcif_scale_align_bits_per_pixel(struct rkcif_device *cif_dev, if (fmt) { switch (fmt->fourcc) { + 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_SBGGR16: case V4L2_PIX_FMT_SGBRG16: case V4L2_PIX_FMT_SGRBG16: @@ -179,21 +311,31 @@ static int rkcif_scale_set_fmt(struct rkcif_scale_vdev *scale_vdev, width = scale_vdev->src_res.width; height = scale_vdev->src_res.height; } - scale_ratio = width / pixm->width; - if (scale_ratio <= 8) { - scale_vdev->scale_mode = SCALE_8TIMES; - scale_times = 8; - } else if (scale_ratio <= 16) { - scale_vdev->scale_mode = SCALE_16TIMES; - scale_times = 16; + if (scale_vdev->scl_mode == RKCIF_SCL_MODE_SCALE) { + scale_ratio = width / pixm->width; + if (scale_ratio <= 8) { + scale_vdev->scale_mode = SCALE_8TIMES; + scale_times = 8; + } else if (scale_ratio <= 16) { + scale_vdev->scale_mode = SCALE_16TIMES; + scale_times = 16; + } else { + scale_vdev->scale_mode = SCALE_32TIMES; + scale_times = 32; + } + //source resolution align (scale_times * 2) + width = ALIGN(width, scale_times * 2); + pixm->width = width / (scale_times * 2) * 2; + pixm->height = height / (scale_times * 2) * 2; } else { - scale_vdev->scale_mode = SCALE_32TIMES; - scale_times = 32; + pixm->width = width / 2; + pixm->height = height / 2; + if (pixm->width % 2 || pixm->height % 2) { + v4l2_err(&scale_vdev->cifdev->v4l2_dev, + "source width/height must multiple of 4\n"); + return -1; + } } - //source resolution align (scale_times * 2) - width = ALIGN(width, scale_times * 2); - pixm->width = width / (scale_times * 2) * 2; - pixm->height = height / (scale_times * 2) * 2; pixm->num_planes = fmt->mplanes; pixm->field = V4L2_FIELD_NONE; pixm->quantization = V4L2_QUANTIZATION_DEFAULT; @@ -543,10 +685,14 @@ static int rkcif_scale_stop(struct rkcif_scale_vdev *scale_vdev) struct rkcif_device *dev = scale_vdev->cifdev; int ch = scale_vdev->ch; - rkcif_write_register_and(dev, CIF_REG_SCL_CH_CTRL, - ~(CIF_SCALE_EN(ch) | - CIF_SCALE_SW_SRC_CH(0x1f, ch) | - CIF_SCALE_SW_MODE(0x03, ch))); + if (dev->chip_id == CHIP_RK3576_CIF) + rkcif_write_register_and(dev, CIF_REG_SCL_CH_CTRL, + ~(CIF_SCALE_EN(ch) | CIF_SCALE_DMA_EN_RK3576)); + else + rkcif_write_register_and(dev, CIF_REG_SCL_CH_CTRL, + ~(CIF_SCALE_EN(ch) | + CIF_SCALE_SW_SRC_CH(0x1f, ch) | + CIF_SCALE_SW_MODE(0x03, ch))); scale_vdev->state = RKCIF_STATE_READY; scale_vdev->frame_idx = 0; return 0; @@ -556,6 +702,7 @@ static void rkcif_scale_vb2_stop_streaming(struct vb2_queue *vq) { struct rkcif_scale_vdev *scale_vdev = vq->drv_priv; struct rkcif_device *dev = scale_vdev->cifdev; + struct rkcif_stream *stream = scale_vdev->stream; struct rkcif_buffer *buf = NULL; int ret = 0; @@ -584,6 +731,8 @@ static void rkcif_scale_vb2_stop_streaming(struct vb2_queue *vq) list_del(&buf->queue); vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); } + if (scale_vdev->scl_mode != RKCIF_SCL_MODE_SCALE) + rkcif_do_stop_stream(stream, RKCIF_STREAM_MODE_TOSCALE); mutex_unlock(&dev->scale_lock); } @@ -820,13 +969,63 @@ static int rkcif_scale_channel_set(struct rkcif_scale_vdev *scale_vdev) rkcif_write_register(dev, get_reg_index_of_scale_vlw(ch), scale_vdev->ch_info.vir_width); val = CIF_SCALE_SW_SRC_CH(scale_vdev->ch_src, ch) | - CIF_SCALE_SW_MODE(scale_vdev->scale_mode, ch) | CIF_SCALE_EN(ch); + + val |= CIF_SCALE_SW_MODE(scale_vdev->scale_mode, ch); + rkcif_write_register_or(dev, CIF_REG_SCL_CH_CTRL, val); return 0; } +static int rkcif_scale_channel_set_rk3576(struct rkcif_scale_vdev *scale_vdev) +{ + struct rkcif_device *dev = scale_vdev->cifdev; + u32 val = 0; + u32 ch = scale_vdev->ch; + + val = rkcif_read_register(dev, CIF_REG_SCL_CH_CTRL); + if (val & CIF_SCALE_EN(ch)) { + v4l2_err(&dev->v4l2_dev, "scale_vdev[%d] has been used by other device\n", ch); + return -EINVAL; + } + + rkcif_assign_scale_buffer_pingpong(scale_vdev, + RKCIF_YUV_ADDR_STATE_INIT, + ch); + rkcif_write_register_or(dev, CIF_REG_SCL_CTRL, SCALE_SOFT_RESET(scale_vdev->ch)); + + rkcif_write_register_and(dev, CIF_REG_GLB_INTST, + ~(SCALE_END_INTSTAT_RK3576 | + SCALE_FIFO_OVERFLOW_RK3576)); + rkcif_write_register_or(dev, CIF_REG_GLB_INTEN, + (SCALE_END_INTSTAT_RK3576 | + SCALE_FIFO_OVERFLOW_RK3576 | + SCALE_TOISP_AXI0_ERR)); + val = CIF_SCALE_SW_WATER_LINE(1); + + rkcif_write_register(dev, CIF_REG_SCL_CTRL, val); + val = scale_vdev->blc.pattern00 | + (scale_vdev->blc.pattern01 << 8) | + (scale_vdev->blc.pattern02 << 16) | + (scale_vdev->blc.pattern03 << 24); + rkcif_write_register(dev, CIF_REG_SCL_BLC_CH0 + ch, + val); + rkcif_write_register(dev, get_reg_index_of_scale_vlw(ch), + scale_vdev->ch_info.vir_width); + val = CIF_SCALE_SW_SRC_CH(scale_vdev->ch_src, ch) | + CIF_SCALE_EN(ch) | CIF_SCALE_DMA_EN_RK3576; + val |= (scale_vdev->scl_mode << 1); + if (scale_vdev->scl_mode == RKCIF_SCL_MODE_SCALE) + val |= CIF_SCALE_SW_MODE_RK3576(scale_vdev->scale_mode); + else if (scale_vdev->scl_mode == RKCIF_SCL_MODE_EXTRACTION) + val |= (scale_vdev->extrac_pattern << 10); + if (!scale_vdev->stream->is_compact) + val |= (1 << 12); + rkcif_write_register_or(dev, CIF_REG_SCL_CH_CTRL, + val); + return 0; +} int rkcif_scale_start(struct rkcif_scale_vdev *scale_vdev) { @@ -842,7 +1041,10 @@ int rkcif_scale_start(struct rkcif_scale_vdev *scale_vdev) } rkcif_scale_channel_init(scale_vdev); - ret = rkcif_scale_channel_set(scale_vdev); + if (dev->chip_id < CHIP_RK3576_CIF) + ret = rkcif_scale_channel_set(scale_vdev); + else + ret = rkcif_scale_channel_set_rk3576(scale_vdev); if (ret) goto destroy_buf; scale_vdev->frame_idx = 0; @@ -877,13 +1079,11 @@ rkcif_scale_vb2_start_streaming(struct vb2_queue *queue, struct rkcif_stream *stream = scale_vdev->stream; int ret = 0; - if (stream->state == RKCIF_STATE_STREAMING) { - stream->to_en_scale = true; - } else { - ret = rkcif_scale_start(scale_vdev); - if (ret) - return ret; - } + ret = rkcif_scale_start(scale_vdev); + if (ret) + return ret; + if (scale_vdev->scl_mode != RKCIF_SCL_MODE_SCALE) + rkcif_do_start_stream(stream, RKCIF_STREAM_MODE_TOSCALE); return 0; } @@ -922,34 +1122,40 @@ static int rkcif_scale_init_vb2_queue(struct vb2_queue *q, } -static int rkcif_scale_g_ch(struct v4l2_device *v4l2_dev, +static int rkcif_scale_g_ch(struct rkcif_device *dev, unsigned int intstat) { + if (dev->chip_id == CHIP_RK3576_CIF) { + if (intstat & SCALE_END_INTSTAT_RK3576) + return 0; + else + return -EINVAL; + } if (intstat & SCALE_END_INTSTAT(0)) { if ((intstat & SCALE_END_INTSTAT(0)) == SCALE_END_INTSTAT(0)) - v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in CH0\n"); + v4l2_warn(&dev->v4l2_dev, "frame0/1 trigger simultaneously in CH0\n"); return RKCIF_SCALE_CH0; } if (intstat & SCALE_END_INTSTAT(1)) { if ((intstat & SCALE_END_INTSTAT(1)) == SCALE_END_INTSTAT(1)) - v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in CH1\n"); + v4l2_warn(&dev->v4l2_dev, "frame0/1 trigger simultaneously in CH1\n"); return RKCIF_SCALE_CH1; } if (intstat & SCALE_END_INTSTAT(2)) { if ((intstat & SCALE_END_INTSTAT(2)) == SCALE_END_INTSTAT(2)) - v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in CH2\n"); + v4l2_warn(&dev->v4l2_dev, "frame0/1 trigger simultaneously in CH2\n"); return RKCIF_SCALE_CH2; } if (intstat & SCALE_END_INTSTAT(3)) { if ((intstat & SCALE_END_INTSTAT(3)) == SCALE_END_INTSTAT(3)) - v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in CH3\n"); + v4l2_warn(&dev->v4l2_dev, "frame0/1 trigger simultaneously in CH3\n"); return RKCIF_SCALE_CH3; } @@ -991,11 +1197,14 @@ static void rkcif_scale_update_stream(struct rkcif_scale_vdev *scale_vdev, int c RKCIF_YUV_ADDR_STATE_UPDATE, ch); - scale_vdev->frame_idx = scale_vdev->stream->frame_idx; + if (scale_vdev->scl_mode != RKCIF_SCL_MODE_SCALE) + scale_vdev->frame_idx++; + else + scale_vdev->frame_idx = scale_vdev->stream->frame_idx; if (active_buf && (!ret)) { vb_done = &active_buf->vb; vb_done->vb2_buf.timestamp = ktime_get_ns(); - vb_done->sequence = scale_vdev->frame_idx; + vb_done->sequence = scale_vdev->frame_idx - 1; rkcif_scale_vb_done_oneframe(scale_vdev, vb_done); } } @@ -1008,10 +1217,13 @@ void rkcif_irq_handle_scale(struct rkcif_device *cif_dev, unsigned int intstat_g int i = 0; u32 val = 0; - val = SCALE_FIFO_OVERFLOW(0) | - SCALE_FIFO_OVERFLOW(1) | - SCALE_FIFO_OVERFLOW(2) | - SCALE_FIFO_OVERFLOW(3); + if (cif_dev->chip_id < CHIP_RK3576_CIF) + val = SCALE_FIFO_OVERFLOW(0) | + SCALE_FIFO_OVERFLOW(1) | + SCALE_FIFO_OVERFLOW(2) | + SCALE_FIFO_OVERFLOW(3); + else + val = SCALE_FIFO_OVERFLOW_RK3576; if (intstat_glb & val) { v4l2_err(&cif_dev->v4l2_dev, "ERROR: scale channel, overflow intstat_glb:0x%x !!\n", @@ -1019,14 +1231,12 @@ void rkcif_irq_handle_scale(struct rkcif_device *cif_dev, unsigned int intstat_g return; } - ch = rkcif_scale_g_ch(&cif_dev->v4l2_dev, - intstat_glb); + ch = rkcif_scale_g_ch(cif_dev, intstat_glb); if (ch < 0) return; for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { - ch = rkcif_scale_g_ch(&cif_dev->v4l2_dev, - intstat_glb); + ch = rkcif_scale_g_ch(cif_dev, intstat_glb); if (ch < 0) continue; @@ -1042,8 +1252,13 @@ void rkcif_irq_handle_scale(struct rkcif_device *cif_dev, unsigned int intstat_g continue; } - scale_vdev->frame_phase = SW_SCALE_END(intstat_glb, ch); - intstat_glb &= ~(SCALE_END_INTSTAT(ch)); + if (cif_dev->chip_id < CHIP_RK3576_CIF) { + scale_vdev->frame_phase = SW_SCALE_END(intstat_glb, ch); + intstat_glb &= ~(SCALE_END_INTSTAT(ch)); + } else { + scale_vdev->frame_phase = SW_SCALE_END_RK3576(intstat_glb); + intstat_glb &= ~(SCALE_END_INTSTAT_RK3576); + } rkcif_scale_update_stream(scale_vdev, ch); stream = scale_vdev->stream; if (stream->to_en_dma) @@ -1074,6 +1289,8 @@ void rkcif_init_scale_vdev(struct rkcif_device *cif_dev, u32 ch) scale_vdev->blc.pattern01 = 0; scale_vdev->blc.pattern02 = 0; scale_vdev->blc.pattern03 = 0; + scale_vdev->scl_mode = RKCIF_SCL_MODE_SCALE; + scale_vdev->extrac_pattern = RKCIF_EXTRACTION_PATTERN_UP_LEFT; INIT_LIST_HEAD(&scale_vdev->buf_head); spin_lock_init(&scale_vdev->vbq_lock); init_waitqueue_head(&scale_vdev->wq_stopped); diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index ac7ae2bc1f7d..ea6ae334c95f 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -67,7 +67,7 @@ static ssize_t rkcif_store_compact_mode(struct device *dev, { struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev); int i, index; - char val[4]; + char val[4] = {0}; if (buf) { index = 0; @@ -195,7 +195,7 @@ static ssize_t rkcif_store_memory_mode(struct device *dev, { struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev); int i, index; - char val[4]; + char val[4] = {0}; if (buf) { index = 0; @@ -256,7 +256,7 @@ static ssize_t rkcif_store_scale_ch0_blc(struct device *dev, unsigned int temp = 0; int ret = 0; int j = 0; - char cha[2] = {0}; + char cha[3] = {0}; if (buf) { index = 0; @@ -326,7 +326,7 @@ static ssize_t rkcif_store_scale_ch1_blc(struct device *dev, unsigned int temp = 0; int ret = 0; int j = 0; - char cha[2] = {0}; + char cha[3] = {0}; if (buf) { index = 0; @@ -398,7 +398,7 @@ static ssize_t rkcif_store_scale_ch2_blc(struct device *dev, unsigned int temp = 0; int ret = 0; int j = 0; - char cha[2] = {0}; + char cha[3] = {0}; if (buf) { index = 0; @@ -469,7 +469,7 @@ static ssize_t rkcif_store_scale_ch3_blc(struct device *dev, unsigned int temp = 0; int ret = 0; int j = 0; - char cha[2] = {0}; + char cha[3] = {0}; if (buf) { index = 0; @@ -527,7 +527,7 @@ static ssize_t rkcif_store_capture_fps(struct device *dev, unsigned int temp = 0; int ret = 0; int j = 0; - char cha[2] = {0}; + char cha[3] = {0}; struct rkcif_fps fps = {0}; if (buf) { @@ -568,7 +568,7 @@ static ssize_t rkcif_store_capture_fps(struct device *dev, return len; } -static DEVICE_ATTR(fps, 0200, NULL, rkcif_store_capture_fps); +static DEVICE_ATTR(fps, 0600, NULL, rkcif_store_capture_fps); static ssize_t rkcif_show_rdbk_debug(struct device *dev, struct device_attribute *attr, @@ -597,7 +597,233 @@ static ssize_t rkcif_store_rdbk_debug(struct device *dev, dev_info(cif_dev->dev, "set rdbk debug failed\n"); return len; } -static DEVICE_ATTR(rdbk_debug, 0200, rkcif_show_rdbk_debug, rkcif_store_rdbk_debug); +static DEVICE_ATTR(rdbk_debug, 0600, rkcif_show_rdbk_debug, rkcif_store_rdbk_debug); + +static ssize_t rkcif_show_scl_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev); + int ret; + + ret = snprintf(buf, PAGE_SIZE, "%d %d %d %d\n", + cif_dev->scale_vdev[0].scl_mode, + cif_dev->scale_vdev[1].scl_mode, + cif_dev->scale_vdev[2].scl_mode, + cif_dev->scale_vdev[3].scl_mode); + return ret; +} + +static ssize_t rkcif_store_scl_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev); + int i, index; + char val[4] = {0}; + unsigned int temp = 0; + int ret = 0; + int j = 0; + char cha[3] = {0}; + + if (buf) { + index = 0; + for (i = 0; i < len; i++) { + if (((buf[i] == ' ') || (buf[i] == '\n')) && j) { + index++; + j = 0; + if (index == 4) + break; + continue; + } else { + if (buf[i] < '0' || buf[i] > '9') + continue; + cha[0] = buf[i]; + cha[1] = '\0'; + ret = kstrtoint(cha, 0, &temp); + if (!ret) { + if (j) + val[index] *= 10; + val[index] += temp; + j++; + } + } + } + + for (i = 0; i < index; i++) { + if (val[i] < 4) + cif_dev->scale_vdev[i].scl_mode = val[i]; + else + dev_info(cif_dev->dev, "set scl_mode failed, out of range\n"); + } + } + + return len; +} + +static DEVICE_ATTR(scl_mode, 0600, + rkcif_show_scl_mode, rkcif_store_scl_mode); + +static ssize_t rkcif_show_extraction_pattern(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev); + int ret; + + ret = snprintf(buf, PAGE_SIZE, "%d %d %d %d\n", + cif_dev->scale_vdev[0].extrac_pattern, + cif_dev->scale_vdev[1].extrac_pattern, + cif_dev->scale_vdev[2].extrac_pattern, + cif_dev->scale_vdev[3].extrac_pattern); + return ret; +} + +static ssize_t rkcif_store_extraction_pattern(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev); + int i, index; + char val[4] = {0}; + unsigned int temp = 0; + int ret = 0; + int j = 0; + char cha[3] = {0}; + + if (buf) { + index = 0; + for (i = 0; i < len; i++) { + if (((buf[i] == ' ') || (buf[i] == '\n')) && j) { + index++; + j = 0; + if (index == 4) + break; + continue; + } else { + if (buf[i] < '0' || buf[i] > '9') + continue; + cha[0] = buf[i]; + cha[1] = '\0'; + ret = kstrtoint(cha, 0, &temp); + if (!ret) { + if (j) + val[index] *= 10; + val[index] += temp; + j++; + } + } + } + + for (i = 0; i < index; i++) { + if (val[i] - '0' < 4) + cif_dev->scale_vdev[i].extrac_pattern = val[i]; + else + dev_info(cif_dev->dev, "set extraction_pattern failed, out of range\n"); + } + } + + return len; +} + +static DEVICE_ATTR(extraction_pattern, 0600, + rkcif_show_extraction_pattern, rkcif_store_extraction_pattern); + +static ssize_t rkcif_show_sw_dbg_en(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev); + int ret; + + ret = snprintf(buf, PAGE_SIZE, "%d %d %d %d\n", + cif_dev->stream[0].sw_dbg_en ? 1 : 0, + cif_dev->stream[1].sw_dbg_en ? 1 : 0, + cif_dev->stream[2].sw_dbg_en ? 1 : 0, + cif_dev->stream[3].sw_dbg_en ? 1 : 0); + return ret; +} + +static ssize_t rkcif_store_sw_dbg_en(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev); + int i, index; + char val[4] = {0}; + + if (cif_dev->chip_id < CHIP_RK3576_CIF) + return len; + + if (buf) { + index = 0; + for (i = 0; i < len; i++) { + if (buf[i] == ' ') + continue; + else if (buf[i] == '\0') + break; + val[index] = buf[i]; + index++; + if (index == 4) + break; + } + + for (i = 0; i < index; i++) { + if (val[i] - '0' == 0) + cif_dev->stream[i].sw_dbg_en = 0; + else + cif_dev->stream[i].sw_dbg_en = 1; + } + } + + return len; +} + +static DEVICE_ATTR(sw_dbg_en, 0600, + rkcif_show_sw_dbg_en, rkcif_store_sw_dbg_en); + +static ssize_t rkcif_show_use_hw_interlace(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev); + int ret; + + ret = snprintf(buf, PAGE_SIZE, "%d\n", + cif_dev->use_hw_interlace); + return ret; +} + +static ssize_t rkcif_store_use_hw_interlace(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev); + int val = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &val); + if (!ret) { + if (val) { + if (cif_dev->inf_id == RKCIF_DVP || + (cif_dev->inf_id == RKCIF_MIPI_LVDS && cif_dev->chip_id > CHIP_RK3562_CIF)) + cif_dev->use_hw_interlace = true; + else + dev_info(cif_dev->dev, "not support to change merge mode of interlaced\n"); + } else { + if (cif_dev->inf_id != RKCIF_DVP) + cif_dev->use_hw_interlace = false; + else + dev_info(cif_dev->dev, "not support to change merge mode of interlaced\n"); + } + } else { + dev_info(cif_dev->dev, "set use_hw_interlace failed\n"); + } + return len; +} + +static DEVICE_ATTR(use_hw_interlace, 0600, + rkcif_show_use_hw_interlace, rkcif_store_use_hw_interlace); static ssize_t rkcif_show_odd_frame_id(struct device *dev, struct device_attribute *attr, @@ -710,6 +936,10 @@ static struct attribute *dev_attrs[] = { &dev_attr_rdbk_debug.attr, &dev_attr_odd_frame_id.attr, &dev_attr_odd_frame_first.attr, + &dev_attr_scl_mode.attr, + &dev_attr_extraction_pattern.attr, + &dev_attr_sw_dbg_en.attr, + &dev_attr_use_hw_interlace.attr, NULL, }; @@ -740,10 +970,15 @@ void rkcif_write_register(struct rkcif_device *dev, csi_offset = dev->csi_host_idx * 0x200; else csi_offset = 0x500; + } else if (dev->chip_id == CHIP_RK3576_CIF) { + if (dev->csi_host_idx < 2) + csi_offset = dev->csi_host_idx * 0x200; + else + csi_offset = 0x100 + dev->csi_host_idx * 0x100; } } if (index < CIF_REG_INDEX_MAX) { - if (index == CIF_REG_DVP_CTRL || reg->offset != 0x0) { + if (index == CIF_REG_GLB_CTRL || index == CIF_REG_DVP_CTRL || reg->offset != 0x0) { write_cif_reg(base, reg->offset + csi_offset, val); v4l2_dbg(4, rkcif_debug, &dev->v4l2_dev, "write reg[0x%x]:0x%x!!!\n", @@ -776,11 +1011,16 @@ void rkcif_write_register_or(struct rkcif_device *dev, csi_offset = dev->csi_host_idx * 0x200; else csi_offset = 0x500; + } else if (dev->chip_id == CHIP_RK3576_CIF) { + if (dev->csi_host_idx < 2) + csi_offset = dev->csi_host_idx * 0x200; + else + csi_offset = 0x100 + dev->csi_host_idx * 0x100; } } if (index < CIF_REG_INDEX_MAX) { - if (index == CIF_REG_DVP_CTRL || reg->offset != 0x0) { + if (index == CIF_REG_GLB_CTRL || index == CIF_REG_DVP_CTRL || reg->offset != 0x0) { reg_val = read_cif_reg(base, reg->offset + csi_offset); reg_val |= val; write_cif_reg(base, reg->offset + csi_offset, reg_val); @@ -815,14 +1055,20 @@ void rkcif_write_register_and(struct rkcif_device *dev, csi_offset = dev->csi_host_idx * 0x200; else csi_offset = 0x500; + } else if (dev->chip_id == CHIP_RK3576_CIF) { + if (dev->csi_host_idx < 2) + csi_offset = dev->csi_host_idx * 0x200; + else + csi_offset = 0x100 + dev->csi_host_idx * 0x100; } } if (index < CIF_REG_INDEX_MAX) { - if (index == CIF_REG_DVP_CTRL || reg->offset != 0x0) { + if (index == CIF_REG_GLB_CTRL || index == CIF_REG_DVP_CTRL || reg->offset != 0x0) { reg_val = read_cif_reg(base, reg->offset + csi_offset); reg_val &= val; write_cif_reg(base, reg->offset + csi_offset, reg_val); + v4l2_dbg(4, rkcif_debug, &dev->v4l2_dev, "write and reg[0x%x]:0x%x!!!\n", reg->offset + csi_offset, val); @@ -854,11 +1100,16 @@ unsigned int rkcif_read_register(struct rkcif_device *dev, csi_offset = dev->csi_host_idx * 0x200; else csi_offset = 0x500; + } else if (dev->chip_id == CHIP_RK3576_CIF) { + if (dev->csi_host_idx < 2) + csi_offset = dev->csi_host_idx * 0x200; + else + csi_offset = 0x100 + dev->csi_host_idx * 0x100; } } if (index < CIF_REG_INDEX_MAX) { - if (index == CIF_REG_DVP_CTRL || reg->offset != 0x0) + if (index == CIF_REG_GLB_CTRL || index == CIF_REG_DVP_CTRL || reg->offset != 0x0) val = read_cif_reg(base, reg->offset + csi_offset); else v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, @@ -1790,9 +2041,7 @@ static int rkcif_register_platform_subdevs(struct rkcif_device *cif_dev) return -EINVAL; } - if (cif_dev->chip_id == CHIP_RK3588_CIF || - cif_dev->chip_id == CHIP_RV1106_CIF || - cif_dev->chip_id == CHIP_RK3562_CIF) { + if (cif_dev->chip_id >= CHIP_RK3588_CIF) { ret = rkcif_register_scale_vdevs(cif_dev, RKCIF_MAX_SCALE_CH, true); if (ret < 0) { @@ -1823,9 +2072,7 @@ static int rkcif_register_platform_subdevs(struct rkcif_device *cif_dev) return 0; err_unreg_stream_vdev: rkcif_unregister_stream_vdevs(cif_dev, stream_num); - if (cif_dev->chip_id == CHIP_RK3588_CIF || - cif_dev->chip_id == CHIP_RV1106_CIF || - cif_dev->chip_id == CHIP_RK3562_CIF) + if (cif_dev->chip_id >= CHIP_RK3588_CIF) rkcif_unregister_scale_vdevs(cif_dev, RKCIF_MAX_SCALE_CH); if (cif_dev->chip_id > CHIP_RK1808_CIF) @@ -2076,9 +2323,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID3); } - if (cif_dev->chip_id == CHIP_RK3588_CIF || - cif_dev->chip_id == CHIP_RV1106_CIF || - cif_dev->chip_id == CHIP_RK3562_CIF) { + if (cif_dev->chip_id >= CHIP_RK3588_CIF) { rkcif_init_scale_vdev(cif_dev, RKCIF_SCALE_CH0); rkcif_init_scale_vdev(cif_dev, RKCIF_SCALE_CH1); rkcif_init_scale_vdev(cif_dev, RKCIF_SCALE_CH2); diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index dfc0a690191c..693e20c1a3aa 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -74,8 +74,8 @@ #define RKCIF_MAX_CSI_CHANNEL 4 #define RKCIF_MAX_PIPELINE 4 -#define RKCIF_DEFAULT_WIDTH 640 -#define RKCIF_DEFAULT_HEIGHT 480 +#define RKCIF_DEFAULT_WIDTH 64 +#define RKCIF_DEFAULT_HEIGHT 48 #define RKCIF_FS_DETECTED_NUM 2 #define RKCIF_MAX_INTERVAL_NS 5000000 @@ -563,6 +563,7 @@ struct rkcif_stream { int last_rx_buf_idx; int last_frame_idx; int new_fource_idx; + int sw_dbg_en; atomic_t buf_cnt; struct completion stop_complete; struct rkcif_toisp_buf_state toisp_buf_state; @@ -728,6 +729,8 @@ struct rkcif_scale_vdev { unsigned int scale_mode; int frame_phase; unsigned int frame_idx; + int scl_mode; + int extrac_pattern; bool stopping; }; diff --git a/drivers/media/platform/rockchip/cif/hw.c b/drivers/media/platform/rockchip/cif/hw.c index 2acf45a7d104..e096da8d30b4 100644 --- a/drivers/media/platform/rockchip/cif/hw.c +++ b/drivers/media/platform/rockchip/cif/hw.c @@ -971,6 +971,113 @@ static const struct cif_reg rk3562_cif_regs[] = { [CIF_REG_TOISP0_CROP] = CIF_REG(TOISP0_CROP), }; +static const char * const rk3576_cif_clks[] = { + "aclk_cif", + "hclk_cif", + "dclk_cif", + "i0clk_cif", + "i1clk_cif", + "i2clk_cif", + "i3clk_cif", + "i4clk_cif", +}; + +static const char * const rk3576_cif_rsts[] = { + "rst_cif_a", + "rst_cif_h", + "rst_cif_d", + "rst_cif_iclk0", + "rst_cif_iclk1", + "rst_cif_iclk2", + "rst_cif_iclk3", + "rst_cif_iclk4", +}; + +static const struct cif_reg rk3576_cif_regs[] = { + [CIF_REG_DVP_CTRL] = CIF_REG(DVP_CTRL), + [CIF_REG_DVP_INTEN] = CIF_REG(DVP_INTEN), + [CIF_REG_DVP_INTSTAT] = CIF_REG(DVP_INTSTAT), + [CIF_REG_DVP_FOR] = CIF_REG(DVP_FOR), + [CIF_REG_DVP_SAV_EAV] = CIF_REG(DVP_SAV_EAV), + [CIF_REG_DVP_FRM0_ADDR_Y] = CIF_REG(DVP_FRM0_ADDR_Y_ID0), + [CIF_REG_DVP_FRM0_ADDR_UV] = CIF_REG(DVP_FRM0_ADDR_UV_ID0), + [CIF_REG_DVP_FRM1_ADDR_Y] = CIF_REG(DVP_FRM1_ADDR_Y_ID0), + [CIF_REG_DVP_FRM1_ADDR_UV] = CIF_REG(DVP_FRM1_ADDR_UV_ID0), + [CIF_REG_DVP_VIR_LINE_WIDTH] = CIF_REG(DVP_VIR_LINE_WIDTH), + [CIF_REG_DVP_SET_SIZE] = CIF_REG(DVP_CROP_SIZE), + [CIF_REG_DVP_CROP] = CIF_REG(DVP_CROP), + [CIF_REG_DVP_LINE_INT_NUM] = CIF_REG(DVP_LINE_INT_NUM_01), + [CIF_REG_DVP_LINE_CNT] = CIF_REG(DVP_LINE_CNT_01), + + [CIF_REG_MIPI_LVDS_ID0_CTRL0] = CIF_REG(CSI_MIPI0_ID0_CTRL0), + [CIF_REG_MIPI_LVDS_ID0_CTRL1] = CIF_REG(CSI_MIPI0_ID0_CTRL1), + [CIF_REG_MIPI_LVDS_ID1_CTRL0] = CIF_REG(CSI_MIPI0_ID1_CTRL0), + [CIF_REG_MIPI_LVDS_ID1_CTRL1] = CIF_REG(CSI_MIPI0_ID1_CTRL1), + [CIF_REG_MIPI_LVDS_ID2_CTRL0] = CIF_REG(CSI_MIPI0_ID2_CTRL0), + [CIF_REG_MIPI_LVDS_ID2_CTRL1] = CIF_REG(CSI_MIPI0_ID2_CTRL1), + [CIF_REG_MIPI_LVDS_ID3_CTRL0] = CIF_REG(CSI_MIPI0_ID3_CTRL0), + [CIF_REG_MIPI_LVDS_ID3_CTRL1] = CIF_REG(CSI_MIPI0_ID3_CTRL1), + [CIF_REG_MIPI_LVDS_CTRL] = CIF_REG(CSI_MIPI0_CTRL), + [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0] = CIF_REG(CSI_MIPI0_FRM0_ADDR_Y_ID0), + [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0] = CIF_REG(CSI_MIPI0_FRM1_ADDR_Y_ID0), + [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0] = CIF_REG(CSI_MIPI0_FRM0_ADDR_UV_ID0), + [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0] = CIF_REG(CSI_MIPI0_FRM1_ADDR_UV_ID0), + [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0] = CIF_REG(CSI_MIPI0_VLW_ID0), + [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1] = CIF_REG(CSI_MIPI0_FRM0_ADDR_Y_ID1), + [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1] = CIF_REG(CSI_MIPI0_FRM1_ADDR_Y_ID1), + [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1] = CIF_REG(CSI_MIPI0_FRM0_ADDR_UV_ID1), + [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1] = CIF_REG(CSI_MIPI0_FRM1_ADDR_UV_ID1), + [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1] = CIF_REG(CSI_MIPI0_VLW_ID1), + [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2] = CIF_REG(CSI_MIPI0_FRM0_ADDR_Y_ID2), + [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2] = CIF_REG(CSI_MIPI0_FRM1_ADDR_Y_ID2), + [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2] = CIF_REG(CSI_MIPI0_FRM0_ADDR_UV_ID2), + [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2] = CIF_REG(CSI_MIPI0_FRM1_ADDR_UV_ID2), + [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2] = CIF_REG(CSI_MIPI0_VLW_ID2), + [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3] = CIF_REG(CSI_MIPI0_FRM0_ADDR_Y_ID3), + [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3] = CIF_REG(CSI_MIPI0_FRM1_ADDR_Y_ID3), + [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3] = CIF_REG(CSI_MIPI0_FRM0_ADDR_UV_ID3), + [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3] = CIF_REG(CSI_MIPI0_FRM1_ADDR_UV_ID3), + [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3] = CIF_REG(CSI_MIPI0_VLW_ID3), + [CIF_REG_MIPI_LVDS_INTEN] = CIF_REG(CSI_MIPI0_INTEN), + [CIF_REG_MIPI_LVDS_INTSTAT] = CIF_REG(CSI_MIPI0_INTSTAT), + [CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1] = CIF_REG(CSI_MIPI0_LINE_INT_NUM_ID0_1_RK3576), + [CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3] = CIF_REG(CSI_MIPI0_LINE_INT_NUM_ID2_3_RK3576), + [CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1] = CIF_REG(CSI_MIPI0_LINE_CNT_ID0_1_RK3576), + [CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3] = CIF_REG(CSI_MIPI0_LINE_CNT_ID2_3_RK3576), + [CIF_REG_MIPI_LVDS_ID0_CROP_START] = CIF_REG(CSI_MIPI0_ID0_CROP_START_RK3576), + [CIF_REG_MIPI_LVDS_ID1_CROP_START] = CIF_REG(CSI_MIPI0_ID1_CROP_START_RK3576), + [CIF_REG_MIPI_LVDS_ID2_CROP_START] = CIF_REG(CSI_MIPI0_ID2_CROP_START_RK3576), + [CIF_REG_MIPI_LVDS_ID3_CROP_START] = CIF_REG(CSI_MIPI0_ID3_CROP_START_RK3576), + [CIF_REG_MIPI_FRAME_NUM_VC0] = CIF_REG(CSI_MIPI0_FRAME_NUM_VC0_RK3576), + [CIF_REG_MIPI_FRAME_NUM_VC1] = CIF_REG(CSI_MIPI0_FRAME_NUM_VC1_RK3576), + [CIF_REG_MIPI_FRAME_NUM_VC2] = CIF_REG(CSI_MIPI0_FRAME_NUM_VC2_RK3576), + [CIF_REG_MIPI_FRAME_NUM_VC3] = CIF_REG(CSI_MIPI0_FRAME_NUM_VC3_RK3576), + [CIF_REG_MIPI_EFFECT_CODE_ID0] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID0_RK3576), + [CIF_REG_MIPI_EFFECT_CODE_ID1] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID1_RK3576), + [CIF_REG_MIPI_EFFECT_CODE_ID2] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID2_RK3576), + [CIF_REG_MIPI_EFFECT_CODE_ID3] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID3_RK3576), + [CIF_REG_MIPI_ON_PAD] = CIF_REG(CSI_MIPI0_ON_PAD_RK3576), + [CIF_REG_MIPI_SET_SIZE_ID0] = CIF_REG(CSI_MIPI0_SET_FRAME_SIZE_ID0_RK3576), + [CIF_REG_MIPI_SET_SIZE_ID1] = CIF_REG(CSI_MIPI0_SET_FRAME_SIZE_ID1_RK3576), + [CIF_REG_MIPI_SET_SIZE_ID2] = CIF_REG(CSI_MIPI0_SET_FRAME_SIZE_ID2_RK3576), + [CIF_REG_MIPI_SET_SIZE_ID3] = CIF_REG(CSI_MIPI0_SET_FRAME_SIZE_ID3_RK3576), + + [CIF_REG_GLB_CTRL] = CIF_REG(GLB_CTRL), + [CIF_REG_GLB_INTEN] = CIF_REG(GLB_INTEN), + [CIF_REG_GLB_INTST] = CIF_REG(GLB_INTST), + + [CIF_REG_SCL_CH_CTRL] = CIF_REG(SCL_CH_CTRL), + [CIF_REG_SCL_CTRL] = CIF_REG(SCL_CTRL), + [CIF_REG_SCL_FRM0_ADDR_CH0] = CIF_REG(SCL_FRM0_ADDR_CH0), + [CIF_REG_SCL_FRM1_ADDR_CH0] = CIF_REG(SCL_FRM1_ADDR_CH0), + [CIF_REG_SCL_VLW_CH0] = CIF_REG(SCL_VLW_CH0), + [CIF_REG_SCL_BLC_CH0] = CIF_REG(SCL_BLC_CH0), + + [CIF_REG_TOISP0_CTRL] = CIF_REG(TOISP0_CH_CTRL), + [CIF_REG_TOISP0_SIZE] = CIF_REG(TOISP0_CROP_SIZE), + [CIF_REG_TOISP0_CROP] = CIF_REG(TOISP0_CROP), +}; + static const struct rkcif_hw_match_data px30_cif_match_data = { .chip_id = CHIP_PX30_CIF, .clks = px30_cif_clks, @@ -1079,6 +1186,15 @@ static const struct rkcif_hw_match_data rk3562_cif_match_data = { .cif_regs = rk3562_cif_regs, }; +static const struct rkcif_hw_match_data rk3576_cif_match_data = { + .chip_id = CHIP_RK3576_CIF, + .clks = rk3576_cif_clks, + .clks_num = ARRAY_SIZE(rk3576_cif_clks), + .rsts = rk3576_cif_rsts, + .rsts_num = ARRAY_SIZE(rk3576_cif_rsts), + .cif_regs = rk3576_cif_regs, +}; + static const struct of_device_id rkcif_plat_of_match[] = { #ifdef CONFIG_CPU_PX30 { @@ -1149,6 +1265,12 @@ static const struct of_device_id rkcif_plat_of_match[] = { .compatible = "rockchip,rk3562-cif", .data = &rk3562_cif_match_data, }, +#endif +#ifdef CONFIG_CPU_RK3576 + { + .compatible = "rockchip,rk3576-cif", + .data = &rk3576_cif_match_data, + }, #endif {}, }; diff --git a/drivers/media/platform/rockchip/cif/hw.h b/drivers/media/platform/rockchip/cif/hw.h index 06ca088c4ce5..7521f4239c11 100644 --- a/drivers/media/platform/rockchip/cif/hw.h +++ b/drivers/media/platform/rockchip/cif/hw.h @@ -107,6 +107,7 @@ enum rkcif_chip_id { CHIP_RK3588_CIF, CHIP_RV1106_CIF, CHIP_RK3562_CIF, + CHIP_RK3576_CIF, }; struct rkcif_hw_match_data { diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.c b/drivers/media/platform/rockchip/cif/mipi-csi2.c index f97efa2bd684..0c2326fb0389 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.c +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.c @@ -146,8 +146,10 @@ static int csi2_enable_clks(struct csi2_hw *csi2_hw) { int ret = 0; - if (!csi2_hw->clks_bulk) - return -EINVAL; + if (!csi2_hw->clks_bulk) { + dev_info(csi2_hw->dev, "clks is NULL, please check it if needs\n"); + return 0; + } ret = clk_bulk_prepare_enable(csi2_hw->clks_num, csi2_hw->clks_bulk); if (ret) @@ -190,6 +192,9 @@ static void csi2_enable(struct csi2_hw *csi2_hw, write_csihost_reg(base, CSIHOST_N_LANES, lanes - 1); + if (csi2->sw_dbg) + val |= BIT(6); + if (host_type == RK_DSI_RXHOST) { val |= SW_DSI_EN(1) | SW_DATATYPE_FS(0x01) | SW_DATATYPE_FE(0x11) | SW_DATATYPE_LS(0x21) | @@ -231,7 +236,8 @@ static int csi2_start(struct csi2_dev *csi2) csi2_hw_do_reset(csi2->csi2_hw[csi_idx]); ret = csi2_enable_clks(csi2->csi2_hw[csi_idx]); if (ret) { - v4l2_err(&csi2->sd, "%s: enable clks failed\n", __func__); + v4l2_err(&csi2->sd, "%s: enable clks failed, index %d\n", + __func__, csi_idx); return ret; } enable_irq(csi2->csi2_hw[csi_idx]->irq1); @@ -587,7 +593,10 @@ static long rkcif_csi2_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg if (csi2->match_data->chip_id > CHIP_RV1126_CSI2) ret = v4l2_subdev_call(sensor, core, ioctl, RKCIF_CMD_SET_CSI_IDX, - arg); + arg); + break; + case RKCIF_CMD_SET_PPI_DATA_DEBUG: + csi2->sw_dbg = *((u32 *)arg); break; default: ret = -ENOIOCTLCMD; @@ -603,6 +612,7 @@ static long rkcif_csi2_compat_ioctl32(struct v4l2_subdev *sd, { void __user *up = compat_ptr(arg); struct rkcif_csi_info csi_info; + int sw_dbg = 0; long ret; switch (cmd) { @@ -612,6 +622,12 @@ static long rkcif_csi2_compat_ioctl32(struct v4l2_subdev *sd, ret = rkcif_csi2_ioctl(sd, cmd, &csi_info); break; + case RKCIF_CMD_SET_PPI_DATA_DEBUG: + if (copy_from_user(&sw_dbg, up, sizeof(int))) + return -EFAULT; + + ret = rkcif_csi2_ioctl(sd, cmd, &sw_dbg); + break; default: ret = -ENOIOCTLCMD; break; @@ -1022,6 +1038,12 @@ static const struct csi2_match_data rk3562_csi2_match_data = { .num_hw = 4, }; +static const struct csi2_match_data rk3576_csi2_match_data = { + .chip_id = CHIP_RK3576_CSI2, + .num_pads = CSI2_NUM_PADS_MAX, + .num_hw = 5, +}; + static const struct of_device_id csi2_dt_ids[] = { { .compatible = "rockchip,rk1808-mipi-csi2", @@ -1051,6 +1073,10 @@ static const struct of_device_id csi2_dt_ids[] = { .compatible = "rockchip,rk3562-mipi-csi2", .data = &rk3562_csi2_match_data, }, + { + .compatible = "rockchip,rk3576-mipi-csi2", + .data = &rk3576_csi2_match_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, csi2_dt_ids); @@ -1204,6 +1230,10 @@ static const struct csi2_hw_match_data rk3562_csi2_hw_match_data = { .chip_id = CHIP_RK3562_CSI2, }; +static const struct csi2_hw_match_data rk3576_csi2_hw_match_data = { + .chip_id = CHIP_RK3576_CSI2, +}; + static const struct of_device_id csi2_hw_ids[] = { { .compatible = "rockchip,rk1808-mipi-csi2-hw", @@ -1231,7 +1261,11 @@ static const struct of_device_id csi2_hw_ids[] = { }, { .compatible = "rockchip,rk3562-mipi-csi2-hw", - .data = &rk3588_csi2_hw_match_data, + .data = &rk3562_csi2_hw_match_data, + }, + { + .compatible = "rockchip,rk3576-mipi-csi2-hw", + .data = &rk3576_csi2_hw_match_data, }, { /* sentinel */ } }; diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.h b/drivers/media/platform/rockchip/cif/mipi-csi2.h index 3306c53d1336..5997abe3cfe6 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.h +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.h @@ -27,8 +27,8 @@ #define CSI2_NUM_PADS_SINGLE_LINK 2 #define MAX_CSI2_SENSORS 2 -#define RKCIF_DEFAULT_WIDTH 640 -#define RKCIF_DEFAULT_HEIGHT 480 +#define RKCIF_DEFAULT_WIDTH 64 +#define RKCIF_DEFAULT_HEIGHT 48 #define CSI_ERRSTR_LEN (256) #define CSI_VCINFO_LEN (12) @@ -94,6 +94,7 @@ enum rkcsi2_chip_id { CHIP_RK3588_CSI2, CHIP_RV1106_CSI2, CHIP_RK3562_CSI2, + CHIP_RK3576_CSI2, }; enum csi2_pads { @@ -171,6 +172,7 @@ struct csi2_dev { int dsi_input_en; struct rkcif_csi_info csi_info; const char *dev_name; + int sw_dbg; }; struct csi2_hw { diff --git a/drivers/media/platform/rockchip/cif/regs.h b/drivers/media/platform/rockchip/cif/regs.h index 68bc6ef30a79..369a5aefa811 100644 --- a/drivers/media/platform/rockchip/cif/regs.h +++ b/drivers/media/platform/rockchip/cif/regs.h @@ -149,6 +149,10 @@ enum cif_reg_index { CIF_REG_MIPI_FRAME_SIZE_ID1, CIF_REG_MIPI_FRAME_SIZE_ID2, CIF_REG_MIPI_FRAME_SIZE_ID3, + CIF_REG_MIPI_SET_SIZE_ID0, + CIF_REG_MIPI_SET_SIZE_ID1, + CIF_REG_MIPI_SET_SIZE_ID2, + CIF_REG_MIPI_SET_SIZE_ID3, CIF_REG_MIPI_ON_PAD, CIF_REG_Y_STAT_CONTROL, @@ -430,6 +434,28 @@ enum cif_reg_index { #define CSI_MIPI0_FRAME_SIZE_ID2 0x1C8 #define CSI_MIPI0_FRAME_SIZE_ID3 0x1CC +#define CSI_MIPI0_LINE_INT_NUM_ID0_1_RK3576 0x1B0 +#define CSI_MIPI0_LINE_INT_NUM_ID2_3_RK3576 0x1B4 +#define CSI_MIPI0_LINE_CNT_ID0_1_RK3576 0x1B8 +#define CSI_MIPI0_LINE_CNT_ID2_3_RK3576 0x1BC +#define CSI_MIPI0_ID0_CROP_START_RK3576 0x190 +#define CSI_MIPI0_ID1_CROP_START_RK3576 0x194 +#define CSI_MIPI0_ID2_CROP_START_RK3576 0x198 +#define CSI_MIPI0_ID3_CROP_START_RK3576 0x19C +#define CSI_MIPI0_FRAME_NUM_VC0_RK3576 0x1D0 +#define CSI_MIPI0_FRAME_NUM_VC1_RK3576 0x1D4 +#define CSI_MIPI0_FRAME_NUM_VC2_RK3576 0x1D8 +#define CSI_MIPI0_FRAME_NUM_VC3_RK3576 0x1DC +#define CSI_MIPI0_EFFECT_CODE_ID0_RK3576 0x180 +#define CSI_MIPI0_EFFECT_CODE_ID1_RK3576 0x184 +#define CSI_MIPI0_EFFECT_CODE_ID2_RK3576 0x188 +#define CSI_MIPI0_EFFECT_CODE_ID3_RK3576 0x18C +#define CSI_MIPI0_ON_PAD_RK3576 0x17C +#define CSI_MIPI0_SET_FRAME_SIZE_ID0_RK3576 0x1A0 +#define CSI_MIPI0_SET_FRAME_SIZE_ID1_RK3576 0x1A4 +#define CSI_MIPI0_SET_FRAME_SIZE_ID2_RK3576 0x1A8 +#define CSI_MIPI0_SET_FRAME_SIZE_ID3_RK3576 0x1AC + /* RV1106 CONTROL Registers Offset */ #define CIF_LVDS0_ID0_CTRL0 0x1D0 #define CIF_LVDS0_ID1_CTRL0 0x1D4 @@ -497,6 +523,10 @@ enum cif_reg_index { #define DVP_SW_WATER_LINE_50 (0x1 << 5) #define DVP_SW_WATER_LINE_25 (0x2 << 5) #define DVP_SW_WATER_LINE_00 (0x3 << 5) +#define DVP_SW_WATER_LINE_75_RK3576 (0x0 << 20) +#define DVP_SW_WATER_LINE_50_RK3576 (0x1 << 20) +#define DVP_SW_WATER_LINE_25_RK3576 (0x2 << 20) +#define DVP_SW_WATER_LINE_00_RK3576 (0x3 << 20) /* CIF_INTEN */ #define INTEN_DISABLE (0x0 << 0) @@ -547,7 +577,9 @@ enum cif_reg_index { #define DVP_SW_PRESS_VALUE(val) (((val) & 0x7) << 13) #define DVP_SW_HURRY_VALUE(val) (((val) & 0x7) << 9) #define DVP_SW_CAP_EN(ID) (2 << ID) +#define DVP_SW_CAP_EN_RK3576(ID) (0x10 << ID) #define DVP_SW_DMA_EN(ID) (0x100000 << ID) +#define DVP_SW_DMA_EN_RK3676(ID) (0x100 << ID) #define DVP_START_INTSTAT(ID) (0x3 << ((ID) * 2)) #define DVP_DMA_END_INTEN(id) \ @@ -633,6 +665,10 @@ enum cif_reg_index { #define BT1120_CLOCK_DOUBLE_EDGES (0x01 << 24) #define BT1120_TRANSMIT_INTERFACE (0x00 << 25) #define BT1120_TRANSMIT_PROGRESS (0x01 << 25) +#define BT1120_TRANSMIT_INTERFACE_RK3588 (0x01 << 9) +#define BT1120_TRANSMIT_PROGRESS_RK3588 (0x00 << 9) +#define BT1120_TRANSMIT_INTERFACE_RK3576 (0x01 << 8) +#define BT1120_TRANSMIT_PROGRESS_RK3576 (0x00 << 8) #define BT1120_YC_SWAP (0x01 << 26) #define BT656_1120_MULTI_ID_DISABLE (0x00 << 28) #define BT656_1120_MULTI_ID_ENABLE (0x01 << 28) @@ -649,12 +685,12 @@ enum cif_reg_index { #define CIF_HIGH_ALIGN_RK3588 (0x01 << 21) #define BT656_DETECT_SAV (0X01 << 13) #define BT656_DETECT_SAV_EAV (0X00 << 13) +#define DVP_UVDS_EN (1 << 14) #define BT1120_CLOCK_SINGLE_EDGES_RK3588 (0x00 << 11) #define BT1120_CLOCK_DOUBLE_EDGES_RK3588 (0x01 << 11) -#define TRANSMIT_INTERFACE_RK3588 (0x01 << 9) -#define TRANSMIT_PROGRESS_RK3588 (0x00 << 9) #define BT1120_YC_SWAP_RK3588 (0x01 << 12) +#define BT1120_YC_SWAP_RK3576 (0x01 << 10) #define INPUT_BT601_YUV422 (0x00 << 2) #define INPUT_BT601_RAW (0x01 << 2) #define INPUT_BT656_YUV422 (0x02 << 2) @@ -748,7 +784,9 @@ enum cif_reg_index { /* CIF SCALE*/ #define SCALE_END_INTSTAT(ch) (0x3 << ((ch + 1) * 2)) +#define SCALE_END_INTSTAT_RK3576 (0x3 << 1) #define SCALE_FIFO_OVERFLOW(ch) (1 << (10 + ch)) +#define SCALE_FIFO_OVERFLOW_RK3576 (1 << 3) #define SCALE_TOISP_AXI0_ERR (1 << 0) #define SCALE_TOISP_AXI1_ERR (1 << 1) #define CIF_SCALE_SW_PRESS_VALUE(val) (((val) & 0x7) << 13) @@ -758,9 +796,12 @@ enum cif_reg_index { #define CIF_SCALE_SW_WATER_LINE(val) (val << 1) #define CIF_SCALE_SW_SRC_CH(val, ch) ((val & 0x1f) << (3 + ch * 8)) #define CIF_SCALE_SW_MODE(val, ch) ((val & 0x3) << (1 + ch * 8)) +#define CIF_SCALE_SW_MODE_RK3576(val) ((val & 0x3) << 8) #define CIF_SCALE_EN(ch) (1 << (ch * 8)) #define SW_SCALE_END(intstat, ch) ((intstat >> ((ch + 1) * 2)) & 0x3) +#define SW_SCALE_END_RK3576(intstat) (intstat >> 1) #define SCALE_SOFT_RESET(ch) (0x1 << (ch + 16)) +#define CIF_SCALE_DMA_EN_RK3576 (1 << 16) /* CIF TOISP*/ #define CIF_TOISP0_FS(ch) (BIT(14) << ch) @@ -768,15 +809,22 @@ enum cif_reg_index { #define CIF_TOISP0_FE(ch) (BIT(20) << ch) #define CIF_TOISP1_FE(ch) (BIT(23) << ch) +#define CIF_TOISP0_FS_RK3576(ch) (BIT(4) << ch) +#define CIF_TOISP0_FE_RK3576(ch) (BIT(7) << ch) + /* CIF_CSI_ID_CTRL0 */ #define CSI_DISABLE_CAPTURE (0x0 << 0) #define CSI_ENABLE_CAPTURE (0x1 << 0) #define CSI_WRDDR_TYPE_RAW8 (0x0 << 1) #define CSI_WRDDR_TYPE_RAW10 (0x1 << 1) #define CSI_WRDDR_TYPE_RAW12 (0x2 << 1) +#define CSI_WRDDR_TYPE_RAW14_RK3588 (0x3 << 0) #define CSI_WRDDR_TYPE_RGB888 (0x3 << 1) +#define CSI_WRDDR_TYPE_RGB888_RK3576 (0x7 << 4) +#define CSI_WRDDR_TYPE_RAW16 (0x4 << 4) #define CSI_WRDDR_TYPE_YUV422 (0x4 << 1) #define CSI_WRDDR_TYPE_YUV420SP (0x5 << 1) +#define CSI_WRDDR_TYPE_YUV420LEGACY (0xB << 4) #define CSI_WRDDR_TYPE_YUV400 (0x6 << 1) #define CSI_WRDDR_TYPE_RGB565 (0x7 << 1) #define CSI_DISABLE_COMMAND_MODE (0x0 << 4) @@ -785,6 +833,8 @@ enum cif_reg_index { #define CSI_ENABLE_CROP (0x1 << 5) #define CSI_DISABLE_CROP_V1 (0x0 << 4) #define CSI_ENABLE_CROP_V1 (0x1 << 4) +#define CSI_DISABLE_CROP_RK3576 (0x0 << 1) +#define CSI_ENABLE_CROP_RK3576 (0x1 << 1) #define CSI_ENABLE_MIPI_COMPACT (0x1 << 6) #define CSI_YUV_INPUT_ORDER_UYVY (0x0 << 16) #define CSI_YUV_INPUT_ORDER_VYUY (0x1 << 16) @@ -792,6 +842,7 @@ enum cif_reg_index { #define CSI_YUV_INPUT_ORDER_YVYU (0x3 << 16) #define CSI_HIGH_ALIGN (0x1 << 31) #define CSI_HIGH_ALIGN_RK3588 (0x1 << 27) +#define CSI_HIGH_ALIGN_RK3576 (0x1 << 11) #define CSI_YUV_OUTPUT_ORDER_UYVY (0x0 << 18) #define CSI_YUV_OUTPUT_ORDER_VYUY (0x1 << 18) @@ -806,6 +857,8 @@ enum cif_reg_index { #define CSI_ALIGN_MSB (0x01 << 27) #define CSI_ALIGN_LSB (0x0 << 27) #define CSI_DMA_ENABLE (0x1 << 28) +#define CSI_DMA_ENABLE_RK3576 (0x1 << 3) +#define CSI_UVDS_EN (1 << 16) #define CSI_NO_HDR (0X0 << 22) #define CSI_HDR2 (0X1 << 22) @@ -893,11 +946,13 @@ enum cif_reg_index { #define CSI_ALL_ERROR_INTEN_V1 (0xf0f << 16) #define CSI_START_INTEN(id) (0x3 << ((id) * 2)) +#define CSI_START_INTEN_RK3576(id) (0x1 << id) #define CSI_DMA_END_INTEN(id) (0x3 << ((id) * 2 + 8)) #define CSI_LINE_INTEN(id) (0x1 << ((id) + 21)) #define CSI_LINE_INTEN_RK3588(id) (0x1 << ((id) + 20)) #define CSI_START_INTSTAT(id) (0x3 << ((id) * 2)) +#define CSI_START_INTSTAT_RK3576(id) (0x1 << id) #define CSI_DMA_END_INTSTAT(id) (0x3 << ((id) * 2 + 8)) #define CSI_LINE_INTSTAT(id) (0x1 << ((id) + 21)) #define CSI_LINE_INTSTAT_V1(id) (0x1 << ((id) + 20)) @@ -1026,6 +1081,10 @@ enum cif_reg_index { #define RKCIF_SKIP_SHIFT 0X15 #define RKCIF_SKIP_EN(x) (0x1 << (8 + x)) +#define RKCIF_CAP_SHIFT_RK3576 0x12 +#define RKCIF_SKIP_SHIFT_RK3576 0x09 +#define RKCIF_SKIP_EN_RK3576 (0x1 << 2) + /* CIF LVDS SAV EAV Define */ #define SW_LVDS_EAV_ACT(code) (((code) & 0xfff) << 16) #define SW_LVDS_SAV_ACT(code) (((code) & 0xfff) << 0) @@ -1072,4 +1131,12 @@ enum cif_reg_index { #define TOISP_END_CH1(index) (0x1 << (21 + index * 3)) #define TOISP_END_CH2(index) (0x1 << (22 + index * 3)) +#define TOISP_FS_CH0_RK3576(index) (0x1 << (4 + index * 3)) +#define TOISP_FS_CH1_RK3576(index) (0x1 << (5 + index * 3)) +#define TOISP_FS_CH2_RK3576(index) (0x1 << (6 + index * 3)) + +#define TOISP_END_CH0_RK3576(index) (0x1 << (7 + index * 3)) +#define TOISP_END_CH1_RK3576(index) (0x1 << (8 + index * 3)) +#define TOISP_END_CH2_RK3576(index) (0x1 << (9 + index * 3)) + #endif diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index e6d403497e56..7085129cdb5d 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -493,10 +493,15 @@ static int sditf_channel_enable(struct sditf_priv *priv, int user) else ch0 = 24;//dvp ctrl_val = (ch0 << 3) | 0x1; - if (user == 0) - int_en = CIF_TOISP0_FS(0) | CIF_TOISP0_FE(0); - else - int_en = CIF_TOISP1_FS(0) | CIF_TOISP1_FE(0); + if (cif_dev->chip_id < CHIP_RK3576_CIF) { + if (user == 0) + int_en = CIF_TOISP0_FS(0) | CIF_TOISP0_FE(0); + else + int_en = CIF_TOISP1_FS(0) | CIF_TOISP1_FE(0); + } else { + if (user == 0) + int_en = CIF_TOISP0_FS_RK3576(0) | CIF_TOISP0_FE_RK3576(0); + } priv->toisp_inf.ch_info[0].is_valid = true; priv->toisp_inf.ch_info[0].id = ch0; } else if (priv->hdr_cfg.hdr_mode == HDR_X2) { @@ -504,12 +509,18 @@ static int sditf_channel_enable(struct sditf_priv *priv, int user) ch1 = cif_dev->csi_host_idx * 4; ctrl_val = (ch0 << 3) | 0x1; ctrl_val |= (ch1 << 11) | 0x100; - if (user == 0) - int_en = CIF_TOISP0_FS(0) | CIF_TOISP0_FS(1) | - CIF_TOISP0_FE(0) | CIF_TOISP0_FE(1); - else - int_en = CIF_TOISP1_FS(0) | CIF_TOISP1_FS(1) | - CIF_TOISP1_FE(0) | CIF_TOISP1_FE(1); + if (cif_dev->chip_id < CHIP_RK3576_CIF) { + if (user == 0) + int_en = CIF_TOISP0_FS(0) | CIF_TOISP0_FS(1) | + CIF_TOISP0_FE(0) | CIF_TOISP0_FE(1); + else + int_en = CIF_TOISP1_FS(0) | CIF_TOISP1_FS(1) | + CIF_TOISP1_FE(0) | CIF_TOISP1_FE(1); + } else { + if (user == 0) + int_en = CIF_TOISP0_FS_RK3576(0) | CIF_TOISP0_FS_RK3576(1) | + CIF_TOISP0_FE_RK3576(0) | CIF_TOISP0_FE_RK3576(1); + } priv->toisp_inf.ch_info[0].is_valid = true; priv->toisp_inf.ch_info[0].id = ch0; priv->toisp_inf.ch_info[1].is_valid = true; @@ -521,12 +532,19 @@ static int sditf_channel_enable(struct sditf_priv *priv, int user) ctrl_val = (ch0 << 3) | 0x1; ctrl_val |= (ch1 << 11) | 0x100; ctrl_val |= (ch2 << 19) | 0x10000; - if (user == 0) - int_en = CIF_TOISP0_FS(0) | CIF_TOISP0_FS(1) | CIF_TOISP0_FS(2) | - CIF_TOISP0_FE(0) | CIF_TOISP0_FE(1) | CIF_TOISP0_FE(2); - else - int_en = CIF_TOISP1_FS(0) | CIF_TOISP1_FS(1) | CIF_TOISP1_FS(2) | - CIF_TOISP1_FE(0) | CIF_TOISP1_FE(1) | CIF_TOISP1_FE(2); + if (cif_dev->chip_id < CHIP_RK3576_CIF) { + if (user == 0) + int_en = CIF_TOISP0_FS(0) | CIF_TOISP0_FS(1) | CIF_TOISP0_FS(2) | + CIF_TOISP0_FE(0) | CIF_TOISP0_FE(1) | CIF_TOISP0_FE(2); + else + int_en = CIF_TOISP1_FS(0) | CIF_TOISP1_FS(1) | CIF_TOISP1_FS(2) | + CIF_TOISP1_FE(0) | CIF_TOISP1_FE(1) | CIF_TOISP1_FE(2); + } else { + if (user == 0) + int_en = CIF_TOISP0_FS_RK3576(0) | CIF_TOISP0_FS_RK3576(1) | + CIF_TOISP0_FS_RK3576(2) | CIF_TOISP0_FE_RK3576(0) | + CIF_TOISP0_FE_RK3576(1) | CIF_TOISP0_FE_RK3576(2); + } priv->toisp_inf.ch_info[0].is_valid = true; priv->toisp_inf.ch_info[0].id = ch0; priv->toisp_inf.ch_info[1].is_valid = true; @@ -534,6 +552,8 @@ static int sditf_channel_enable(struct sditf_priv *priv, int user) priv->toisp_inf.ch_info[2].is_valid = true; priv->toisp_inf.ch_info[2].id = ch2; } + if (cif_dev->chip_id > CHIP_RK3562_CIF) + ctrl_val |= BIT(28); if (user == 0) { if (priv->toisp_inf.link_mode == TOISP_UNITE) width = priv->cap_info.width / 2 + RKMOUDLE_UNITE_EXTEND_PIXEL; diff --git a/include/uapi/linux/rkcif-config.h b/include/uapi/linux/rkcif-config.h index c9b9bbf0d301..3b9958e31679 100644 --- a/include/uapi/linux/rkcif-config.h +++ b/include/uapi/linux/rkcif-config.h @@ -39,6 +39,21 @@ #define RKCIF_CMD_SET_QUICK_STREAM \ _IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct rkcif_quick_stream_param) +#define RKCIF_CMD_GET_SCL_MODE \ + _IOR('V', BASE_VIDIOC_PRIVATE + 9, unsigned int) + +#define RKCIF_CMD_SET_SCL_MODE \ + _IOW('V', BASE_VIDIOC_PRIVATE + 10, unsigned int) + +#define RKCIF_CMD_GET_EXTRACTION_PATTERN \ + _IOR('V', BASE_VIDIOC_PRIVATE + 11, unsigned int) + +#define RKCIF_CMD_SET_EXTRACTION_PATTERN \ + _IOW('V', BASE_VIDIOC_PRIVATE + 12, unsigned int) + +#define RKCIF_CMD_SET_PPI_DATA_DEBUG \ + _IOW('V', BASE_VIDIOC_PRIVATE + 13, unsigned int) + /* cif memory mode * 0: raw12/raw10/raw8 8bit memory compact * 1: raw12/raw10 16bit memory one pixel @@ -88,4 +103,16 @@ struct rkcif_quick_stream_param { int resume_mode; }; +enum rkcif_scl_mode { + RKCIF_SCL_MODE_SCALE, + RKCIF_SCL_MODE_BINNING, + RKCIF_SCL_MODE_EXTRACTION, +}; + +enum rkcif_extraction_pattern { + RKCIF_EXTRACTION_PATTERN_UP_LEFT, + RKCIF_EXTRACTION_PATTERN_UP_RIGHT, + RKCIF_EXTRACTION_PATTERN_BOTTOM_LEFT, + RKCIF_EXTRACTION_PATTERN_BOTTOM_RIGHT, +}; #endif