diff --git a/drivers/media/platform/rockchip/isp/capture.c b/drivers/media/platform/rockchip/isp/capture.c index 48993849b9de..01cc876e7598 100644 --- a/drivers/media/platform/rockchip/isp/capture.c +++ b/drivers/media/platform/rockchip/isp/capture.c @@ -1137,6 +1137,125 @@ static int rkisp_enum_framesizes(struct file *file, void *prov, return 0; } +static int rkisp_get_cmsk(struct rkisp_stream *stream, struct rkisp_cmsk_cfg *cfg) +{ + struct rkisp_device *dev = stream->ispdev; + unsigned long lock_flags = 0; + u32 i, win_en, mode; + + if (dev->isp_ver != ISP_V30 || stream->id == RKISP_STREAM_FBC) { + v4l2_err(&dev->v4l2_dev, "%s not support\n", __func__); + return -EINVAL; + } + + spin_lock_irqsave(&dev->cmsk_lock, lock_flags); + *cfg = dev->cmsk_cfg; + spin_unlock_irqrestore(&dev->cmsk_lock, lock_flags); + + switch (stream->id) { + case RKISP_STREAM_MP: + win_en = cfg->win[0].win_en; + mode = cfg->win[0].mode; + break; + case RKISP_STREAM_SP: + win_en = cfg->win[1].win_en; + mode = cfg->win[1].mode; + break; + case RKISP_STREAM_BP: + default: + win_en = cfg->win[2].win_en; + mode = cfg->win[2].mode; + break; + } + + cfg->width_ro = dev->isp_sdev.out_crop.width; + cfg->height_ro = dev->isp_sdev.out_crop.height; + for (i = 0; i < RKISP_CMSK_WIN_MAX; i++) { + cfg->win[i].win_en = !!(win_en & BIT(i)); + cfg->win[i].mode = !!(mode & BIT(i)); + } + + return 0; +} + +static int rkisp_set_cmsk(struct rkisp_stream *stream, struct rkisp_cmsk_cfg *cfg) +{ + struct rkisp_device *dev = stream->ispdev; + unsigned long lock_flags = 0; + u8 i, win_en = 0, mode = 0; + u16 h_offs, v_offs, h_size, v_size; + u32 width = dev->isp_sdev.out_crop.width; + u32 height = dev->isp_sdev.out_crop.height; + bool warn = false; + + if (dev->isp_ver != ISP_V30 || stream->id == RKISP_STREAM_FBC) { + v4l2_err(&dev->v4l2_dev, "%s not support\n", __func__); + return -EINVAL; + } + + spin_lock_irqsave(&dev->cmsk_lock, lock_flags); + dev->is_cmsk_upd = true; + for (i = 0; i < RKISP_CMSK_WIN_MAX; i++) { + win_en |= cfg->win[i].win_en ? BIT(i) : 0; + mode |= cfg->win[i].mode ? BIT(i) : 0; + + if (cfg->win[i].win_en) { + if (cfg->win[i].mode) { + dev->cmsk_cfg.win[i].cover_color_y = cfg->win[i].cover_color_y; + dev->cmsk_cfg.win[i].cover_color_u = cfg->win[i].cover_color_u; + dev->cmsk_cfg.win[i].cover_color_v = cfg->win[i].cover_color_v; + } + h_offs = cfg->win[i].h_offs & ~0x1; + v_offs = cfg->win[i].v_offs & ~0x1; + h_size = cfg->win[i].h_size & ~0x7; + v_size = cfg->win[i].v_size & ~0x7; + if (h_offs != cfg->win[i].h_offs || + v_offs != cfg->win[i].v_offs || + h_size != cfg->win[i].h_size || + v_size != cfg->win[i].v_size) + warn = true; + if (h_offs + h_size > width) { + h_size = (width - h_offs) & ~0x7; + warn = true; + } + if (v_offs + v_size > height) { + v_size = (height - v_offs) & ~0x7; + warn = true; + } + if (warn) { + warn = false; + v4l2_warn(&dev->v4l2_dev, + "%s cmsk offs 2 align, size 8 align and offs + size < resolution\n" + "\t cmsk win%d result to offs:%d %d, size:%d %d\n", + stream->vnode.vdev.name, i, h_offs, v_offs, h_size, v_size); + } + dev->cmsk_cfg.win[i].h_offs = h_offs; + dev->cmsk_cfg.win[i].v_offs = v_offs; + dev->cmsk_cfg.win[i].h_size = h_size; + dev->cmsk_cfg.win[i].v_size = v_size; + } + } + + switch (stream->id) { + case RKISP_STREAM_MP: + dev->cmsk_cfg.win[0].win_en = win_en; + dev->cmsk_cfg.win[0].mode = mode; + break; + case RKISP_STREAM_SP: + dev->cmsk_cfg.win[1].win_en = win_en; + dev->cmsk_cfg.win[1].mode = mode; + break; + case RKISP_STREAM_BP: + default: + dev->cmsk_cfg.win[2].win_en = win_en; + dev->cmsk_cfg.win[2].mode = mode; + break; + } + spin_unlock_irqrestore(&dev->cmsk_lock, lock_flags); + return 0; + +} + static long rkisp_ioctl_default(struct file *file, void *fh, bool valid_prio, unsigned int cmd, void *arg) { @@ -1174,6 +1293,12 @@ static long rkisp_ioctl_default(struct file *file, void *fh, stream->memory = SW_CSI_RWA_WR_SIMG_SWP | SW_CSI_RAW_WR_SIMG_MODE; break; + case RKISP_CMD_GET_CMSK: + ret = rkisp_get_cmsk(stream, arg); + break; + case RKISP_CMD_SET_CMSK: + ret = rkisp_set_cmsk(stream, arg); + break; default: ret = -EINVAL; } diff --git a/drivers/media/platform/rockchip/isp/dev.c b/drivers/media/platform/rockchip/isp/dev.c index 971b485170d6..101a1b662289 100644 --- a/drivers/media/platform/rockchip/isp/dev.c +++ b/drivers/media/platform/rockchip/isp/dev.c @@ -459,8 +459,10 @@ static int _set_pipeline_default_fmt(struct rkisp_device *dev) rkisp_dmarx_set_fmt(&dev->dmarx_dev.stream[i], pixm); rkisp_set_stream_def_fmt(dev, RKISP_STREAM_FBC, width, height, V4L2_PIX_FMT_FBC0); +#ifdef RKISP_STREAM_BP_EN rkisp_set_stream_def_fmt(dev, RKISP_STREAM_BP, width, height, V4L2_PIX_FMT_NV12); +#endif } return 0; } diff --git a/drivers/media/platform/rockchip/isp/dev.h b/drivers/media/platform/rockchip/isp/dev.h index 15b5d5bcd888..e057491111fa 100644 --- a/drivers/media/platform/rockchip/isp/dev.h +++ b/drivers/media/platform/rockchip/isp/dev.h @@ -230,5 +230,9 @@ struct rkisp_device { u8 filt_state[RDBK_F_MAX]; struct rkisp_rx_buf_pool pv_pool[RKISP_RX_BUF_POOL_MAX]; + + spinlock_t cmsk_lock; + struct rkisp_cmsk_cfg cmsk_cfg; + bool is_cmsk_upd; }; #endif diff --git a/drivers/media/platform/rockchip/isp/regs_v3x.h b/drivers/media/platform/rockchip/isp/regs_v3x.h index 06ffafd7e0ef..60b63a872209 100644 --- a/drivers/media/platform/rockchip/isp/regs_v3x.h +++ b/drivers/media/platform/rockchip/isp/regs_v3x.h @@ -25,31 +25,36 @@ #define ISP3X_CMSK_BASE 0x00000230 #define ISP3X_CMSK_CTRL0 (ISP3X_CMSK_BASE + 0x00000) #define ISP3X_CMSK_CTRL1 (ISP3X_CMSK_BASE + 0x00004) -#define ISP3X_CMSK_PIC_SIZE (ISP3X_CMSK_BASE + 0x00008) -#define ISP3X_CMSK_YUV0 (ISP3X_CMSK_BASE + 0x0000C) -#define ISP3X_CMSK_YUV1 (ISP3X_CMSK_BASE + 0x00010) -#define ISP3X_CMSK_YUV2 (ISP3X_CMSK_BASE + 0x00014) -#define ISP3X_CMSK_YUV3 (ISP3X_CMSK_BASE + 0x00018) -#define ISP3X_CMSK_YUV4 (ISP3X_CMSK_BASE + 0x0001C) -#define ISP3X_CMSK_YUV5 (ISP3X_CMSK_BASE + 0x00020) -#define ISP3X_CMSK_YUV6 (ISP3X_CMSK_BASE + 0x00024) -#define ISP3X_CMSK_YUV7 (ISP3X_CMSK_BASE + 0x00028) -#define ISP3X_CMSK_OFFS0 (ISP3X_CMSK_BASE + 0x0002C) -#define ISP3X_CMSK_SIZE0 (ISP3X_CMSK_BASE + 0x00030) -#define ISP3X_CMSK_OFFS1 (ISP3X_CMSK_BASE + 0x00034) -#define ISP3X_CMSK_SIZE1 (ISP3X_CMSK_BASE + 0x00038) -#define ISP3X_CMSK_OFFS2 (ISP3X_CMSK_BASE + 0x0003C) -#define ISP3X_CMSK_SIZE2 (ISP3X_CMSK_BASE + 0x00040) -#define ISP3X_CMSK_OFFS3 (ISP3X_CMSK_BASE + 0x00044) -#define ISP3X_CMSK_SIZE3 (ISP3X_CMSK_BASE + 0x00048) -#define ISP3X_CMSK_OFFS4 (ISP3X_CMSK_BASE + 0x0004C) -#define ISP3X_CMSK_SIZE4 (ISP3X_CMSK_BASE + 0x00050) -#define ISP3X_CMSK_OFFS5 (ISP3X_CMSK_BASE + 0x00054) -#define ISP3X_CNSK_SIZE5 (ISP3X_CMSK_BASE + 0x00058) -#define ISP3X_CMSK_OFFS6 (ISP3X_CMSK_BASE + 0x0005C) -#define ISP3X_CNSK_SIZE6 (ISP3X_CMSK_BASE + 0x00060) -#define ISP3X_CMSK_OFFS7 (ISP3X_CMSK_BASE + 0x00064) -#define ISP3X_CNSK_SIZE7 (ISP3X_CMSK_BASE + 0x00068) +#define ISP3X_CMSK_CTRL2 (ISP3X_CMSK_BASE + 0x00008) +#define ISP3X_CMSK_CTRL3 (ISP3X_CMSK_BASE + 0x0000c) +#define ISP3X_CMSK_CTRL4 (ISP3X_CMSK_BASE + 0x00010) +#define ISP3X_CMSK_CTRL5 (ISP3X_CMSK_BASE + 0x00014) +#define ISP3X_CMSK_CTRL6 (ISP3X_CMSK_BASE + 0x00018) +#define ISP3X_CMSK_PIC_SIZE (ISP3X_CMSK_BASE + 0x0001c) +#define ISP3X_CMSK_YUV0 (ISP3X_CMSK_BASE + 0x00020) +#define ISP3X_CMSK_YUV1 (ISP3X_CMSK_BASE + 0x00024) +#define ISP3X_CMSK_YUV2 (ISP3X_CMSK_BASE + 0x00028) +#define ISP3X_CMSK_YUV3 (ISP3X_CMSK_BASE + 0x0002c) +#define ISP3X_CMSK_YUV4 (ISP3X_CMSK_BASE + 0x00030) +#define ISP3X_CMSK_YUV5 (ISP3X_CMSK_BASE + 0x00034) +#define ISP3X_CMSK_YUV6 (ISP3X_CMSK_BASE + 0x00038) +#define ISP3X_CMSK_YUV7 (ISP3X_CMSK_BASE + 0x0003c) +#define ISP3X_CMSK_OFFS0 (ISP3X_CMSK_BASE + 0x00050) +#define ISP3X_CMSK_SIZE0 (ISP3X_CMSK_BASE + 0x00054) +#define ISP3X_CMSK_OFFS1 (ISP3X_CMSK_BASE + 0x00058) +#define ISP3X_CMSK_SIZE1 (ISP3X_CMSK_BASE + 0x0005c) +#define ISP3X_CMSK_OFFS2 (ISP3X_CMSK_BASE + 0x00060) +#define ISP3X_CMSK_SIZE2 (ISP3X_CMSK_BASE + 0x00064) +#define ISP3X_CMSK_OFFS3 (ISP3X_CMSK_BASE + 0x00068) +#define ISP3X_CMSK_SIZE3 (ISP3X_CMSK_BASE + 0x0006c) +#define ISP3X_CMSK_OFFS4 (ISP3X_CMSK_BASE + 0x00070) +#define ISP3X_CMSK_SIZE4 (ISP3X_CMSK_BASE + 0x00074) +#define ISP3X_CMSK_OFFS5 (ISP3X_CMSK_BASE + 0x00078) +#define ISP3X_CMSK_SIZE5 (ISP3X_CMSK_BASE + 0x0007c) +#define ISP3X_CMSK_OFFS6 (ISP3X_CMSK_BASE + 0x00080) +#define ISP3X_CMSK_SIZE6 (ISP3X_CMSK_BASE + 0x00084) +#define ISP3X_CMSK_OFFS7 (ISP3X_CMSK_BASE + 0x00088) +#define ISP3X_CMSK_SIZE7 (ISP3X_CMSK_BASE + 0x0008c) #define ISP3X_SUPER_IMP_BASE 0x00000300 #define ISP3X_SUPER_IMP_CTRL (ISP3X_SUPER_IMP_BASE + 0x00000) @@ -1537,6 +1542,16 @@ #define ISP3X_SW_MIPI2ISP_FIFO_DIS BIT(25) #define ISP3X_SW_3D_DBR_START_MODE BIT(26) +/* CMSK */ +#define ISP3X_SW_CMSK_EN BIT(0) +#define ISP3X_SW_CMSK_EN_MP BIT(1) +#define ISP3X_SW_CMSK_EN_SP BIT(2) +#define ISP3X_SW_CMSK_EN_BP BIT(3) +#define ISP3X_SW_CMSK_BLKSIZE(x) (((x) & 3) << 4) +#define ISP3X_SW_CMSK_ORDER_MODE BIT(1) + +#define ISP3X_SW_CMSK_YUV(x, y, z) (((x) & 0xff) | ((y) & 0xff) << 8 | ((z) & 0xff) << 16) + /* ISP CTRL0 */ #define ISP3X_SW_CGC_YUV_LIMIT BIT(28) #define ISP3X_SW_CGC_RATIO_EN BIT(29) diff --git a/drivers/media/platform/rockchip/isp/rkisp.c b/drivers/media/platform/rockchip/isp/rkisp.c index cfeb7ca3bdc1..d9e89fb4edaf 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.c +++ b/drivers/media/platform/rockchip/isp/rkisp.c @@ -83,6 +83,8 @@ * +---------------------------------------------------------+ */ +static void rkisp_config_cmsk(struct rkisp_device *dev); + struct backup_reg { const u32 base; const u32 shd; @@ -559,7 +561,7 @@ void rkisp_trigger_read_back(struct rkisp_device *dev, u8 dma2frm, u32 mode, boo &dev->isp_sdev.in_fmt, dev->isp_sdev.quantization); rkisp_params_cfg(params_vdev, cur_frame_id); - + rkisp_config_cmsk(dev); if (!hw->is_single && !is_try) { rkisp_update_regs(dev, CTRL_VI_ISP_PATH, SUPER_IMP_COLOR_CR); rkisp_update_regs(dev, DUAL_CROP_M_H_OFFS, DUAL_CROP_S_V_SIZE); @@ -1126,6 +1128,73 @@ static void rkisp_config_color_space(struct rkisp_device *dev) CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA, false); } +static void rkisp_config_cmsk(struct rkisp_device *dev) +{ + unsigned long lock_flags = 0; + u32 i, val, mp_en, sp_en, bp_en, ctrl = 0; + struct rkisp_cmsk_cfg cfg; + + if (dev->isp_ver != ISP_V30) + return; + + spin_lock_irqsave(&dev->cmsk_lock, lock_flags); + if (!dev->is_cmsk_upd) { + spin_unlock_irqrestore(&dev->cmsk_lock, lock_flags); + return; + } + dev->is_cmsk_upd = false; + cfg = dev->cmsk_cfg; + spin_unlock_irqrestore(&dev->cmsk_lock, lock_flags); + + mp_en = cfg.win[0].win_en; + if (mp_en) { + ctrl |= ISP3X_SW_CMSK_EN_MP; + rkisp_write(dev, ISP3X_CMSK_CTRL1, mp_en, false); + val = cfg.win[0].mode; + rkisp_write(dev, ISP3X_CMSK_CTRL4, val, false); + } + + sp_en = cfg.win[1].win_en; + if (sp_en) { + ctrl |= ISP3X_SW_CMSK_EN_SP; + rkisp_write(dev, ISP3X_CMSK_CTRL2, sp_en, false); + val = cfg.win[1].mode; + rkisp_write(dev, ISP3X_CMSK_CTRL5, val, false); + } + + bp_en = cfg.win[2].win_en; + if (bp_en) { + ctrl |= ISP3X_SW_CMSK_EN_BP; + rkisp_write(dev, ISP3X_CMSK_CTRL3, bp_en, false); + val = cfg.win[2].mode; + rkisp_write(dev, ISP3X_CMSK_CTRL6, val, false); + } + + for (i = 0; i < RKISP_CMSK_WIN_MAX; i++) { + if (!(mp_en & BIT(i)) && !(sp_en & BIT(i)) && !(bp_en & BIT(i))) + continue; + + val = ISP3X_SW_CMSK_YUV(cfg.win[i].cover_color_y, + cfg.win[i].cover_color_u, + cfg.win[i].cover_color_v); + rkisp_write(dev, ISP3X_CMSK_YUV0 + i * 4, val, false); + + val = ISP_PACK_2SHORT(cfg.win[i].h_offs, cfg.win[i].v_offs); + rkisp_write(dev, ISP3X_CMSK_OFFS0 + i * 8, val, false); + + val = ISP_PACK_2SHORT(cfg.win[i].h_size, cfg.win[i].v_size); + rkisp_write(dev, ISP3X_CMSK_SIZE0 + i * 8, val, false); + } + + if (ctrl) { + val = ISP_PACK_2SHORT(dev->isp_sdev.out_crop.width, + dev->isp_sdev.out_crop.height); + rkisp_write(dev, ISP3X_CMSK_PIC_SIZE, val, false); + ctrl |= ISP3X_SW_CMSK_EN | ISP3X_SW_CMSK_ORDER_MODE; + } + rkisp_write(dev, ISP3X_CMSK_CTRL0, ctrl, false); +} + /* * configure isp blocks with input format, size...... */ @@ -1281,6 +1350,8 @@ static int rkisp_config_isp(struct rkisp_device *dev) rkisp_update_regs(dev, CIF_ISP_ACQ_H_OFFS, CIF_ISP_ACQ_V_SIZE); rkisp_update_regs(dev, CIF_ISP_OUT_H_SIZE, CIF_ISP_OUT_V_SIZE); } + + rkisp_config_cmsk(dev); return 0; } @@ -1623,6 +1694,8 @@ end: dev->isp_ver == ISP_V21 || dev->isp_ver == ISP_V30) kfifo_reset(&dev->rdbk_kfifo); + if (dev->isp_ver == ISP_V30) + memset(&dev->cmsk_cfg, 0, sizeof(dev->cmsk_cfg)); if (dev->emd_vc <= CIF_ISP_ADD_DATA_VC_MAX) { for (i = 0; i < RKISP_EMDDATA_FIFO_MAX; i++) kfifo_free(&dev->emd_data_fifo[i].mipi_kfifo); @@ -2890,6 +2963,7 @@ int rkisp_register_isp_subdev(struct rkisp_device *isp_dev, struct v4l2_subdev *sd = &isp_sdev->sd; int ret; + spin_lock_init(&isp_dev->cmsk_lock); spin_lock_init(&isp_dev->rdbk_lock); ret = kfifo_alloc(&isp_dev->rdbk_kfifo, 16 * sizeof(struct isp2x_csi_trigger), GFP_KERNEL); @@ -3295,6 +3369,9 @@ vs_skip: if ((isp_mis & CIF_ISP_FRAME) && dev->stats_vdev.rdbk_mode) rkisp_stats_rdbk_enable(&dev->stats_vdev, false); + + if (!IS_HDR_RDBK(dev->hdr.op_mode)) + rkisp_config_cmsk(dev); } /* diff --git a/include/uapi/linux/rkisp2-config.h b/include/uapi/linux/rkisp2-config.h index 68f59ef7f460..7d036b141aad 100644 --- a/include/uapi/linux/rkisp2-config.h +++ b/include/uapi/linux/rkisp2-config.h @@ -49,6 +49,12 @@ #define RKISP_CMD_SET_CSI_MEMORY_MODE \ _IOW('V', BASE_VIDIOC_PRIVATE + 101, int) +#define RKISP_CMD_GET_CMSK \ + _IOR('V', BASE_VIDIOC_PRIVATE + 102, struct rkisp_cmsk_cfg) + +#define RKISP_CMD_SET_CMSK \ + _IOW('V', BASE_VIDIOC_PRIVATE + 103, struct rkisp_cmsk_cfg) + /*************************************************************/ #define ISP2X_ID_DPCC (0) @@ -243,6 +249,50 @@ struct isp2x_mesh_head { u32 data_oft; } __attribute__ ((packed)); +#define RKISP_CMSK_WIN_MAX 8 +#define RKISP_CMSK_MOSAIC_MODE 0 +#define RKISP_CMSK_COVER_MODE 1 + +/* struct rkisp_cmsk_win + * Priacy Mask Window configture, support 8 windows, and + * support for mainpath and selfpath output stream channel. + * + * mode: 0:mosaic mode, 1:cover mode + * win_index: window index 0~7. windows overlap, priority win7 > win0. + * cover_color_y: cover mode effective, share for stream channel when same win_index. + * cover_color_u: cover mode effective, share for stream channel when same win_index. + * cover_color_v: cover mode effective, share for stream channel when same win_index. + * + * h_offs: window horizontal offset, share for stream channel when same win_index. 2 align. + * v_offs: window vertical offset, share for stream channel when same win_index. 2 align. + * h_size: window horizontal size, share for stream channel when same win_index. 8 align. + * v_size: window vertical size, share for stream channel when same win_index. 8 align. + */ +struct rkisp_cmsk_win { + unsigned char mode; + unsigned char win_en; + + unsigned char cover_color_y; + unsigned char cover_color_u; + unsigned char cover_color_v; + + unsigned short h_offs; + unsigned short v_offs; + unsigned short h_size; + unsigned short v_size; +} __attribute__ ((packed)); + +/* struct rkisp_cmsk_cfg + * win: priacy mask window + * width_ro: isp full resolution, h_offs + h_size <= width_ro. + * height_ro: isp full resolution, v_offs + v_size <= height_ro. + */ +struct rkisp_cmsk_cfg { + struct rkisp_cmsk_win win[RKISP_CMSK_WIN_MAX]; + unsigned int width_ro; + unsigned int height_ro; +} __attribute__ ((packed)); + /* trigger event mode * T_TRY: trigger maybe with retry * T_TRY_YES: trigger to retry