diff --git a/drivers/media/platform/rockchip/vpss/vpss_offline.c b/drivers/media/platform/rockchip/vpss/vpss_offline.c index c33ef0dde7d6..c022139970ad 100644 --- a/drivers/media/platform/rockchip/vpss/vpss_offline.c +++ b/drivers/media/platform/rockchip/vpss/vpss_offline.c @@ -583,7 +583,7 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) bool ch_en = false; ktime_t t = 0; s64 us = 0; - int ret, i; + int ret, i, tile_num = 0; bool wr_uv_swap = false; if (rkvpss_debug >= 2) { @@ -714,6 +714,20 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) in_size = cfg->input.stride * cfg->input.height * 3; in_ctrl |= RKVPSS_MI_RD_INPUT_422SP | RKVPSS_MI_RD_FBCD_YUV444_EN; break; + case V4L2_PIX_FMT_TILE420: + if (cfg->input.stride < ALIGN(cfg->input.width * 6, 16)) + cfg->input.stride = ALIGN(cfg->input.width * 6, 16); + in_c_offs = 0; + in_size = cfg->input.stride * (cfg->input.height / 4); + in_ctrl |= RKVPSS_MI_RD_INPUT_420SP; + break; + case V4L2_PIX_FMT_TILE422: + if (cfg->input.stride < ALIGN(cfg->input.width * 8, 16)) + cfg->input.stride = ALIGN(cfg->input.width * 8, 16); + in_c_offs = 0; + in_size = cfg->input.stride * (cfg->input.height / 4); + in_ctrl |= RKVPSS_MI_RD_INPUT_422SP; + break; default: v4l2_err(&ofl->v4l2_dev, "dev_id:%d no support input format:%c%c%c%c\n", cfg->dev_id, cfg->input.format, cfg->input.format >> 8, @@ -736,19 +750,37 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) cfg->output[i].crop_v_offs = ALIGN(cfg->output[i].crop_v_offs, 2); cfg->output[i].crop_width = ALIGN(cfg->output[i].crop_width, 2); cfg->output[i].crop_height = ALIGN(cfg->output[i].crop_height, 2); - if (cfg->output[i].crop_width + cfg->output[i].crop_h_offs > cfg->input.width) { - v4l2_err(&ofl->v4l2_dev, "dev_id:%d ech%d inval crop(offs:%d w:%d) input width:%d\n", - i, cfg->dev_id, cfg->output[i].crop_h_offs, - cfg->output[i].crop_width, cfg->input.width); - cfg->output[i].crop_h_offs = 0; - cfg->output[i].crop_width = cfg->input.width; - } - if (cfg->output[i].crop_height + cfg->output[i].crop_v_offs > cfg->input.height) { - v4l2_err(&ofl->v4l2_dev, "dev_id:%d ch%d inval crop(offs:%d h:%d) input height:%d\n", - cfg->dev_id, i, cfg->output[i].crop_v_offs, - cfg->output[i].crop_height, cfg->input.height); - cfg->output[i].crop_v_offs = 0; - cfg->output[i].crop_height = cfg->input.height; + + if (!cfg->input.rotate || cfg->input.rotate == 2) { + if (cfg->output[i].crop_width + cfg->output[i].crop_h_offs > cfg->input.width) { + v4l2_err(&ofl->v4l2_dev, "dev_id:%d ech%d inval crop(offs:%d w:%d) input width:%d\n", + i, cfg->dev_id, cfg->output[i].crop_h_offs, + cfg->output[i].crop_width, cfg->input.width); + cfg->output[i].crop_h_offs = 0; + cfg->output[i].crop_width = cfg->input.width; + } + if (cfg->output[i].crop_height + cfg->output[i].crop_v_offs > cfg->input.height) { + v4l2_err(&ofl->v4l2_dev, "dev_id:%d ch%d inval crop(offs:%d h:%d) input height:%d\n", + cfg->dev_id, i, cfg->output[i].crop_v_offs, + cfg->output[i].crop_height, cfg->input.height); + cfg->output[i].crop_v_offs = 0; + cfg->output[i].crop_height = cfg->input.height; + } + } else { + if (cfg->output[i].crop_width + cfg->output[i].crop_h_offs > cfg->input.height) { + v4l2_err(&ofl->v4l2_dev, "dev_id:%d ech%d rotate inval crop(offs:%d w:%d) input height:%d\n", + i, cfg->dev_id, cfg->output[i].crop_h_offs, + cfg->output[i].crop_width, cfg->input.height); + cfg->output[i].crop_h_offs = 0; + cfg->output[i].crop_width = cfg->input.height; + } + if (cfg->output[i].crop_height + cfg->output[i].crop_v_offs > cfg->input.width) { + v4l2_err(&ofl->v4l2_dev, "dev_id:%d ch%d rotate inval crop(offs:%d h:%d) input width:%d\n", + cfg->dev_id, i, cfg->output[i].crop_v_offs, + cfg->output[i].crop_height, cfg->input.width); + cfg->output[i].crop_v_offs = 0; + cfg->output[i].crop_height = cfg->input.width; + } } if (i == RKVPSS_OUTPUT_CH2 || i == RKVPSS_OUTPUT_CH3) { @@ -864,6 +896,20 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) out_ch[i].size = cfg->output[i].stride * h * 3 / 2; out_ch[i].c_offs = cfg->output[i].stride * h; break; + case V4L2_PIX_FMT_TILE420: + if (cfg->output[i].stride < ALIGN(w * 6, 16)) + cfg->output[i].stride = ALIGN(w * 6, 16); + out_ch[i].ctrl |= RKVPSS_MI_CHN_WR_OUTPUT_YUV420; + out_ch[i].size = cfg->output[i].stride * (h / 4); + out_ch[i].c_offs = 0; + break; + case V4L2_PIX_FMT_TILE422: + if (cfg->output[i].stride < ALIGN(w * 8, 16)) + cfg->output[i].stride = ALIGN(w * 8, 16); + out_ch[i].ctrl |= RKVPSS_MI_CHN_WR_OUTPUT_YUV422; + out_ch[i].size = cfg->output[i].stride * (h / 4); + out_ch[i].c_offs = 0; + 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, @@ -899,6 +945,24 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) in_ctrl |= RKVPSS_MI_RD_MODE(2) | RKVPSS_MI_RD_FBCD_OPT_DIS; rkvpss_hw_write(hw, RKVPSS_MI_RD_Y_STRIDE, 0); } else { + if (cfg->input.format == V4L2_PIX_FMT_TILE420 || + cfg->input.format == V4L2_PIX_FMT_TILE422) { + in_ctrl |= RKVPSS_MI_RD_MODE(1); + switch (cfg->input.rotate) { + case 1: + in_ctrl |= RKVPSS_MI_RD_ROT_90; + break; + case 2: + in_ctrl |= RKVPSS_MI_RD_ROT_180; + break; + case 3: + in_ctrl |= RKVPSS_MI_RD_ROT_270; + break; + default: + in_ctrl |= RKVPSS_MI_RD_ROT_0; + break; + } + } val = cfg->input.stride; rkvpss_hw_write(hw, RKVPSS_MI_RD_Y_STRIDE, val); } @@ -956,7 +1020,12 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) val = cfg->output[i].stride; rkvpss_hw_write(hw, reg + i * 0x100, val); reg = RKVPSS_MI_CHN0_WR_Y_SIZE; - val = cfg->output[i].stride * h; + + if (cfg->output[i].format == V4L2_PIX_FMT_TILE420 || + cfg->output[i].format == V4L2_PIX_FMT_TILE422) + val = cfg->output[i].stride * (ALIGN(h, 4) / 4); + else + val = cfg->output[i].stride * h; rkvpss_hw_write(hw, reg + i * 0x100, val); reg = RKVPSS_MI_CHN0_WR_CB_SIZE; val = out_ch[i].size - val; @@ -966,7 +1035,9 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) val = out_ch[i].ctrl; rkvpss_hw_write(hw, reg + i * 0x100, val); - if (cfg->output[i].flip) { + if (cfg->output[i].flip && + !(cfg->output[i].format == V4L2_PIX_FMT_TILE420) && + !(cfg->output[i].format == V4L2_PIX_FMT_TILE422)) { flip_en |= RKVPSS_MI_CHN_V_FLIP(i); switch (cfg->output[i].format) { @@ -1026,6 +1097,21 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg) } } + for (i = 0; i < 2; i++) { + if (cfg->output[i].format == V4L2_PIX_FMT_TILE420 || + cfg->output[i].format == V4L2_PIX_FMT_TILE422) { + tile_num++; + if (tile_num > 1) { + v4l2_err(&ofl->v4l2_dev, + "dev_id:%d only one ch can tile write\n", cfg->dev_id); + return -EINVAL; + } + mask = RKVPSS_MI_WR_TILE_SEL(3); + val = RKVPSS_MI_WR_TILE_SEL(i + 1); + rkvpss_hw_set_bits(hw, RKVPSS_MI_WR_CTRL, mask, val); + } + } + rkvpss_hw_write(hw, RKVPSS_MI_WR_INIT, mi_update); mask = 0; diff --git a/include/uapi/linux/rk-video-format.h b/include/uapi/linux/rk-video-format.h index 05907e6454ff..e08139a05786 100644 --- a/include/uapi/linux/rk-video-format.h +++ b/include/uapi/linux/rk-video-format.h @@ -23,6 +23,10 @@ #define V4l2_PIX_FMT_EBD8 v4l2_fourcc('E', 'B', 'D', '8') /* shield pix data 16-bit */ #define V4l2_PIX_FMT_SPD16 v4l2_fourcc('S', 'P', 'D', '6') +/* yuv420 tile */ +#define V4L2_PIX_FMT_TILE420 v4l2_fourcc('T', 'I', 'L', '0') +/* yuv422 tile */ +#define V4L2_PIX_FMT_TILE422 v4l2_fourcc('T', 'I', 'L', '2') /* Vendor specific - used for Rockchip ISP1 camera sub-system */ #define V4L2_META_FMT_RK_ISP1_PARAMS v4l2_fourcc('R', 'K', '1', 'P') /* Rockchip ISP1 params */ diff --git a/include/uapi/linux/rk-vpss-config.h b/include/uapi/linux/rk-vpss-config.h index 7932051131cf..4973433ff2e1 100644 --- a/include/uapi/linux/rk-vpss-config.h +++ b/include/uapi/linux/rk-vpss-config.h @@ -187,7 +187,9 @@ struct rkvpss_module_sel { * 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 + * V4L2_PIX_FMT_TILE420/V4L2_PIX_FMT_TILE422 for tile * buf_fd: dmabuf fd of input image buf + * rotate: 0:rotate0 1:rotate90 2:rotate180; 3:rotate270, note:only tile input support rotate */ struct rkvpss_input_cfg { int width; @@ -195,6 +197,7 @@ struct rkvpss_input_cfg { int stride; int format; int buf_fd; + int rotate; } __attribute__ ((packed)); /* struct rkvpss_output_cfg __________________ @@ -213,6 +216,7 @@ struct rkvpss_input_cfg { * 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. + * V4L2_PIX_FMT_TILE420/V4L2_PIX_FMT_TILE422 for tile, ch0 or ch1 support tile * flip: flip enable * buf_fd: dmabuf fd of output image buf * cmsc: cover and mosaic configure