diff --git a/drivers/media/platform/rockchip/vpss/regs.h b/drivers/media/platform/rockchip/vpss/regs.h index afeb2a5f6570..5d9442cbb720 100644 --- a/drivers/media/platform/rockchip/vpss/regs.h +++ b/drivers/media/platform/rockchip/vpss/regs.h @@ -1054,7 +1054,7 @@ /* MI_WR_CTRL */ #define RKVPSS_MI_WR_INIT_BASE_EN BIT(4) -#define RKVPSS_MI_WR_UV_SWAP BIT(7) +#define RKVPSS_MI_WR_UV_SWAP BIT(5) #define RKVPSS_MI_WR_TILE_SEL(x) (((x) & 0x3) << 8) #define RKVPSS_MI_WR_STRIDE_CFG_DIS BIT(15) #define RKVPSS_MI_WR_GROUP_MODE(x) (((x) & 0x3) << 16) diff --git a/drivers/media/platform/rockchip/vpss/stream.c b/drivers/media/platform/rockchip/vpss/stream.c index 6ab31d905fef..5443bcc78ba7 100644 --- a/drivers/media/platform/rockchip/vpss/stream.c +++ b/drivers/media/platform/rockchip/vpss/stream.c @@ -62,6 +62,33 @@ static const struct capture_fmt scl_fmts[] = { .swap = 0, .wr_fmt = RKVPSS_MI_CHN_WR_422P, .output_fmt = RKVPSS_MI_CHN_WR_OUTPUT_YUV422, + }, { + .fourcc = V4L2_PIX_FMT_NV61, + .fmt_type = FMT_YUV, + .bpp = { 8, 16 }, + .cplanes = 2, + .mplanes = 1, + .swap = 0, + .wr_fmt = RKVPSS_MI_CHN_WR_42XSP, + .output_fmt = RKVPSS_MI_CHN_WR_OUTPUT_YUV422, + }, { + .fourcc = V4L2_PIX_FMT_NV21, + .fmt_type = FMT_YUV, + .bpp = { 8, 16 }, + .cplanes = 2, + .mplanes = 1, + .swap = 0, + .wr_fmt = RKVPSS_MI_CHN_WR_42XSP, + .output_fmt = RKVPSS_MI_CHN_WR_OUTPUT_YUV420, + }, { + .fourcc = V4L2_PIX_FMT_VYUY, + .fmt_type = FMT_YUV, + .bpp = { 16 }, + .cplanes = 1, + .mplanes = 1, + .swap = 0, + .wr_fmt = RKVPSS_MI_CHN_WR_422P, + .output_fmt = RKVPSS_MI_CHN_WR_OUTPUT_YUV422, } }; @@ -129,6 +156,60 @@ static const struct capture_fmt scl1_fmts[] = { .wr_fmt = 0, .swap = 0, .output_fmt = RKVPSS_MI_CHN_WR_OUTPUT_ARGB888, + }, { + .fourcc = V4L2_PIX_FMT_RGB565X, + .fmt_type = FMT_RGB, + .bpp = { 16 }, + .mplanes = 1, + .cplanes = 1, + .wr_fmt = 0, + .swap = 0, + .output_fmt = RKVPSS_MI_CHN_WR_OUTPUT_RGB565, + }, { + .fourcc = V4L2_PIX_FMT_BGR24, + .fmt_type = FMT_RGB, + .bpp = { 24 }, + .mplanes = 1, + .cplanes = 1, + .wr_fmt = 0, + .swap = 0, + .output_fmt = RKVPSS_MI_CHN_WR_OUTPUT_RGB888, + }, { + .fourcc = V4L2_PIX_FMT_XRGB32, + .fmt_type = FMT_RGB, + .bpp = { 32 }, + .mplanes = 1, + .cplanes = 1, + .wr_fmt = 0, + .swap = RKVPSS_MI_CHN_WR_RB_SWAP, + .output_fmt = RKVPSS_MI_CHN_WR_OUTPUT_ARGB888, + }, { + .fourcc = V4L2_PIX_FMT_NV61, + .fmt_type = FMT_YUV, + .bpp = { 8, 16 }, + .cplanes = 2, + .mplanes = 1, + .swap = 0, + .wr_fmt = RKVPSS_MI_CHN_WR_42XSP, + .output_fmt = RKVPSS_MI_CHN_WR_OUTPUT_YUV422, + }, { + .fourcc = V4L2_PIX_FMT_NV21, + .fmt_type = FMT_YUV, + .bpp = { 8, 16 }, + .cplanes = 2, + .mplanes = 1, + .swap = 0, + .wr_fmt = RKVPSS_MI_CHN_WR_42XSP, + .output_fmt = RKVPSS_MI_CHN_WR_OUTPUT_YUV420, + }, { + .fourcc = V4L2_PIX_FMT_VYUY, + .fmt_type = FMT_YUV, + .bpp = { 16 }, + .cplanes = 1, + .mplanes = 1, + .swap = 0, + .wr_fmt = RKVPSS_MI_CHN_WR_422P, + .output_fmt = RKVPSS_MI_CHN_WR_OUTPUT_YUV422, } }; @@ -455,7 +536,7 @@ static void scl_config_mi(struct rkvpss_stream *stream) struct rkvpss_device *dev = stream->dev; struct capture_fmt *fmt = &stream->out_cap_fmt; struct v4l2_pix_format_mplane *out_fmt = &stream->out_fmt; - u32 reg, val; + u32 reg, val, mask; val = out_fmt->plane_fmt[0].bytesperline; reg = stream->config->mi.stride; @@ -463,9 +544,11 @@ static void scl_config_mi(struct rkvpss_stream *stream) switch (fmt->fourcc) { case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: val = out_fmt->plane_fmt[0].bytesperline / 2; break; case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_XRGB32: val = out_fmt->plane_fmt[0].bytesperline / 4; break; default: @@ -495,6 +578,15 @@ static void scl_config_mi(struct rkvpss_stream *stream) reg = stream->config->mi.ctrl; rkvpss_write(dev, reg, val); + switch (fmt->fourcc) { + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_VYUY: + mask = RKVPSS_MI_WR_UV_SWAP; + val = RKVPSS_MI_WR_UV_SWAP; + rkvpss_hw_set_bits(dev->hw_dev, RKVPSS_MI_WR_CTRL, mask, val); + } + stream->is_mf_upd = true; rkvpss_frame_end(stream); } @@ -1007,6 +1099,44 @@ static void rkvpss_stop_streaming(struct vb2_queue *queue) mutex_unlock(&hw->dev_lock); } +static int check_wr_uvswap(struct rkvpss_stream *stream) +{ + struct rkvpss_device *dev = stream->dev; + struct rkvpss_stream *check_stream; + struct capture_fmt *fmt; + bool wr_uv_swap = false; + int i, ret = 0; + + for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { + check_stream = &dev->stream_vdev.stream[i]; + if (check_stream->streaming) { + fmt = &check_stream->out_cap_fmt; + switch (fmt->fourcc) { + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_VYUY: + wr_uv_swap = true; + break; + default: + break; + } + } + } + if (wr_uv_swap) { + switch (stream->out_cap_fmt.fourcc) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_UYVY: + v4l2_err(&dev->v4l2_dev, "wr_uv_swap need to be consistent\n"); + ret = -EINVAL; + break; + default: + break; + } + } + + return ret; +} static int rkvpss_stream_start(struct rkvpss_stream *stream) { int ret = 0; @@ -1016,6 +1146,9 @@ static int rkvpss_stream_start(struct rkvpss_stream *stream) if (ret < 0) return ret; ret = rkvpss_stream_crop(stream, true, true); + if (ret < 0) + return ret; + ret = check_wr_uvswap(stream); if (ret < 0) return ret; diff --git a/drivers/media/platform/rockchip/vpss/vpss_offline.c b/drivers/media/platform/rockchip/vpss/vpss_offline.c index e516aae2ff57..c33ef0dde7d6 100644 --- a/drivers/media/platform/rockchip/vpss/vpss_offline.c +++ b/drivers/media/platform/rockchip/vpss/vpss_offline.c @@ -584,6 +584,7 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) ktime_t t = 0; s64 us = 0; int ret, i; + bool wr_uv_swap = false; if (rkvpss_debug >= 2) { v4l2_info(&ofl->v4l2_dev, @@ -626,24 +627,72 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) in_size = cfg->input.stride * cfg->input.height * 3 / 2; in_ctrl |= RKVPSS_MI_RD_INPUT_420SP; break; + case V4L2_PIX_FMT_NV61: + if (cfg->input.stride < ALIGN(cfg->input.width, 16)) + cfg->input.stride = ALIGN(cfg->input.width, 16); + in_c_offs = cfg->input.stride * cfg->input.height; + in_size = cfg->input.stride * cfg->input.height * 2; + in_ctrl |= RKVPSS_MI_RD_INPUT_422SP | RKVPSS_MI_RD_UV_SWAP; + break; + case V4L2_PIX_FMT_NV21: + if (cfg->input.stride < ALIGN(cfg->input.width, 16)) + cfg->input.stride = ALIGN(cfg->input.width, 16); + in_c_offs = cfg->input.stride * cfg->input.height; + in_size = cfg->input.stride * cfg->input.height * 3 / 2; + in_ctrl |= RKVPSS_MI_RD_INPUT_420SP | RKVPSS_MI_RD_UV_SWAP; + break; case V4L2_PIX_FMT_RGB565: if (cfg->input.stride < ALIGN(cfg->input.width * 2, 16)) cfg->input.stride = ALIGN(cfg->input.width * 2, 16); in_size = cfg->input.stride * cfg->input.height; in_ctrl |= RKVPSS_MI_RD_INPUT_BGR565; break; + case V4L2_PIX_FMT_RGB565X: + if (cfg->input.stride < ALIGN(cfg->input.width * 2, 16)) + cfg->input.stride = ALIGN(cfg->input.width * 2, 16); + in_size = cfg->input.stride * cfg->input.height; + in_ctrl |= RKVPSS_MI_RD_INPUT_BGR565 | RKVPSS_MI_RD_RB_SWAP; + break; case V4L2_PIX_FMT_RGB24: if (cfg->input.stride < ALIGN(cfg->input.width * 3, 16)) cfg->input.stride = ALIGN(cfg->input.width * 3, 16); in_size = cfg->input.stride * cfg->input.height; in_ctrl |= RKVPSS_MI_RD_INPUT_BGR888; break; + case V4L2_PIX_FMT_BGR24: + if (cfg->input.stride < ALIGN(cfg->input.width * 3, 16)) + cfg->input.stride = ALIGN(cfg->input.width * 3, 16); + in_size = cfg->input.stride * cfg->input.height; + in_ctrl |= RKVPSS_MI_RD_INPUT_BGR888 | RKVPSS_MI_RD_RB_SWAP; + break; + case V4L2_PIX_FMT_XRGB32: + if (cfg->input.stride < ALIGN(cfg->input.width * 4, 16)) + cfg->input.stride = ALIGN(cfg->input.width * 4, 16); + in_size = cfg->input.stride * cfg->input.height; + in_ctrl |= RKVPSS_MI_RD_INPUT_ABGR888 | RKVPSS_MI_RD_RB_SWAP; + break; case V4L2_PIX_FMT_XBGR32: if (cfg->input.stride < ALIGN(cfg->input.width * 4, 16)) cfg->input.stride = ALIGN(cfg->input.width * 4, 16); in_size = cfg->input.stride * cfg->input.height; in_ctrl |= RKVPSS_MI_RD_INPUT_ABGR888 | RKVPSS_MI_RD_RB_SWAP; break; + case V4L2_PIX_FMT_RGBX32: + if (cfg->input.stride < ALIGN(cfg->input.width * 4, 16)) + cfg->input.stride = ALIGN(cfg->input.width * 4, 16); + in_size = cfg->input.stride * cfg->input.height; + in_ctrl |= RKVPSS_MI_RD_INPUT_ABGR888 + | RKVPSS_MI_RD_RB_SWAP + | RKVPSS_MI_RD_ALPHA_SWAP; + break; + case V4L2_PIX_FMT_BGRX32: + if (cfg->input.stride < ALIGN(cfg->input.width * 4, 16)) + cfg->input.stride = ALIGN(cfg->input.width * 4, 16); + in_size = cfg->input.stride * cfg->input.height; + in_ctrl |= RKVPSS_MI_RD_INPUT_ABGR888 + | RKVPSS_MI_RD_RB_SWAP + | RKVPSS_MI_RD_ALPHA_SWAP; + break; case V4L2_PIX_FMT_FBC0: if (cfg->input.stride < ALIGN(cfg->input.width, 16)) cfg->input.stride = ALIGN(cfg->input.width, 16); @@ -730,7 +779,7 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) switch (cfg->output[i].format) { case V4L2_PIX_FMT_RGB565: if (cfg->output[i].stride < ALIGN(w * 2, 16)) - cfg->output[i].stride = ALIGN(w * 3, 16); + cfg->output[i].stride = ALIGN(w * 2, 16); out_ch[i].ctrl |= RKVPSS_MI_CHN_WR_OUTPUT_RGB565 | RKVPSS_MI_CHN_WR_RB_SWAP; break; case V4L2_PIX_FMT_RGB24: @@ -738,11 +787,27 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) cfg->output[i].stride = ALIGN(w * 3, 16); out_ch[i].ctrl |= RKVPSS_MI_CHN_WR_OUTPUT_RGB888 | RKVPSS_MI_CHN_WR_RB_SWAP; break; + case V4L2_PIX_FMT_RGB565X: + if (cfg->output[i].stride < ALIGN(w * 2, 16)) + cfg->output[i].stride = ALIGN(w * 2, 16); + out_ch[i].ctrl |= RKVPSS_MI_CHN_WR_OUTPUT_RGB565; + break; + case V4L2_PIX_FMT_BGR24: + if (cfg->output[i].stride < ALIGN(w * 3, 16)) + cfg->output[i].stride = ALIGN(w * 3, 16); + out_ch[i].ctrl |= RKVPSS_MI_CHN_WR_OUTPUT_RGB888; + break; case V4L2_PIX_FMT_XBGR32: if (cfg->output[i].stride < ALIGN(w * 4, 16)) cfg->output[i].stride = ALIGN(w * 4, 16); out_ch[i].ctrl |= RKVPSS_MI_CHN_WR_OUTPUT_ARGB888; break; + case V4L2_PIX_FMT_XRGB32: + if (cfg->output[i].stride < ALIGN(w * 4, 16)) + cfg->output[i].stride = ALIGN(w * 4, 16); + out_ch[i].ctrl |= RKVPSS_MI_CHN_WR_OUTPUT_ARGB888 + | RKVPSS_MI_CHN_WR_RB_SWAP; + break; default: is_fmt_find = false; } @@ -779,6 +844,26 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) out_ch[i].ctrl |= RKVPSS_MI_CHN_WR_42XSP | RKVPSS_MI_CHN_WR_OUTPUT_YUV400; out_ch[i].size = cfg->output[i].stride * h; break; + case V4L2_PIX_FMT_VYUY: + if (cfg->output[i].stride < ALIGN(w * 2, 16)) + cfg->output[i].stride = ALIGN(w * 2, 16); + out_ch[i].ctrl |= RKVPSS_MI_CHN_WR_422P | RKVPSS_MI_CHN_WR_OUTPUT_YUV422; + out_ch[i].size = cfg->output[i].stride * h; + break; + case V4L2_PIX_FMT_NV61: + if (cfg->output[i].stride < ALIGN(w, 16)) + cfg->output[i].stride = ALIGN(w, 16); + out_ch[i].ctrl |= RKVPSS_MI_CHN_WR_42XSP | RKVPSS_MI_CHN_WR_OUTPUT_YUV422; + out_ch[i].size = cfg->output[i].stride * h * 2; + out_ch[i].c_offs = cfg->output[i].stride * h; + break; + case V4L2_PIX_FMT_NV21: + if (cfg->output[i].stride < ALIGN(w, 16)) + cfg->output[i].stride = ALIGN(w, 16); + out_ch[i].ctrl |= RKVPSS_MI_CHN_WR_42XSP | RKVPSS_MI_CHN_WR_OUTPUT_YUV420; + out_ch[i].size = cfg->output[i].stride * h * 3 / 2; + out_ch[i].c_offs = cfg->output[i].stride * h; + break; default: v4l2_err(&ofl->v4l2_dev, "dev_id:%d no support output ch%d format:%c%c%c%c\n", cfg->dev_id, i, @@ -886,9 +971,11 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) switch (cfg->output[i].format) { case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: val = cfg->output[i].stride / 2; break; case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_XRGB32: val = cfg->output[i].stride / 4; break; default: @@ -903,8 +990,42 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) } rkvpss_hw_write(hw, RKVPSS_CROP0_CTRL, crop_en); rkvpss_hw_write(hw, RKVPSS_CROP0_UPDATE, RKVPSS_CROP_FORCE_UPD); + if (flip_en) rkvpss_hw_set_bits(hw, RKVPSS_MI_WR_VFLIP_CTRL, mask, flip_en); + + for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { + if (cfg->output[i].enable && + (cfg->output[i].format == V4L2_PIX_FMT_VYUY || + cfg->output[i].format == V4L2_PIX_FMT_NV21 || + cfg->output[i].format == V4L2_PIX_FMT_NV61)) + wr_uv_swap = true; + } + + if (wr_uv_swap) { + for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { + if (cfg->output[i].enable && (cfg->output[i].format == V4L2_PIX_FMT_UYVY || + cfg->output[i].format == V4L2_PIX_FMT_NV12 || + cfg->output[i].format == V4L2_PIX_FMT_NV16)) { + v4l2_err(&ofl->v4l2_dev, + "dev_id:%d wr_uv_swap need to be consistent\n", + cfg->dev_id); + return -EAGAIN; + } + } + } + + for (i = 0; i < RKVPSS_OUTPUT_MAX; i++) { + if (cfg->output[i].format == V4L2_PIX_FMT_VYUY || + cfg->output[i].format == V4L2_PIX_FMT_NV21 || + cfg->output[i].format == V4L2_PIX_FMT_NV61) { + mask = RKVPSS_MI_WR_UV_SWAP; + val = RKVPSS_MI_WR_UV_SWAP; + rkvpss_hw_set_bits(hw, RKVPSS_MI_WR_CTRL, mask, val); + break; + } + } + rkvpss_hw_write(hw, RKVPSS_MI_WR_INIT, mi_update); mask = 0; diff --git a/include/uapi/linux/rk-vpss-config.h b/include/uapi/linux/rk-vpss-config.h index 9f372346cf83..7932051131cf 100644 --- a/include/uapi/linux/rk-vpss-config.h +++ b/include/uapi/linux/rk-vpss-config.h @@ -183,7 +183,9 @@ struct rkvpss_module_sel { * width: width of input image, range: 32~4672 * height: height of input image, range: 32~3504 * stride: virtual width of input image, 16 align. auto calculate according to width and format if 0. - * format: V4L2_PIX_FMT_NV12/V4L2_PIX_FMT_NV16/V4L2_PIX_FMT_RGB565/V4L2_PIX_FMT_RGB24/V4L2_PIX_FMT_XBGR32 + * format: V4L2_PIX_FMT_NV12/V4L2_PIX_FMT_NV16/V4L2_PIX_FMT_RGB565/V4L2_PIX_FMT_RGB24/V4L2_PIX_FMT_XBGR32/ + * V4L2_PIX_FMT_NV61/V4L2_PIX_FMT_NV21/V4L2_PIX_FMT_RGB565X/V4L2_PIX_FMT_BGR24/V4L2_PIX_FMT_XRGB32/ + * V4L2_PIX_FMT_RGBX32/V4L2_PIX_FMT_BGRX32 * V4L2_PIX_FMT_FBC0/V4L2_PIX_FMT_FBC2/V4L2_PIX_FMT_FBC4 for rkfbcd * buf_fd: dmabuf fd of input image buf */ @@ -206,8 +208,11 @@ struct rkvpss_input_cfg { * scl_width: scale width. CH0 1~8 scale range. CH1/CH2/CH3 1~32 scale range. CH2/CH3 max 1080p with scale. * scl_height: scale height. CH0 1~6 scale range. CH1/CH2/CH3 1~32 scale range. CH2/CH3 max 1080p with scale. * stride: virtual width of output image, 16 align. auto calculate according to width and format if 0. - * format: V4L2_PIX_FMT_NV12/V4L2_PIX_FMT_NV16/V4L2_PIX_FMT_GREY/V4L2_PIX_FMT_UYVY for all channel. - * V4L2_PIX_FMT_RGB565/V4L2_PIX_FMT_RGB24/V4L2_PIX_FMT_XBGR32 only for RKVPSS_OUTPUT_CH1. + * format: V4L2_PIX_FMT_NV12/V4L2_PIX_FMT_NV16/V4L2_PIX_FMT_GREY/V4L2_PIX_FMT_UYVY/ + * V4L2_PIX_FMT_VYUY/V4L2_PIX_FMT_NV21/V4L2_PIX_FMT_NV61 for all channel. + * NOTE:V,LSB is for all channel + * V4L2_PIX_FMT_RGB565/V4L2_PIX_FMT_RGB24/V4L2_PIX_FMT_XBGR32/V4L2_PIX_FMT_RGB565X/V4L2_PIX_FMT_BGR24/ + * V4L2_PIX_FMT_XRGB32 only for RKVPSS_OUTPUT_CH1. * flip: flip enable * buf_fd: dmabuf fd of output image buf * cmsc: cover and mosaic configure