diff --git a/drivers/media/platform/rockchip/isp/dev.h b/drivers/media/platform/rockchip/isp/dev.h index 5c5e17ab303f..1670cec2488c 100644 --- a/drivers/media/platform/rockchip/isp/dev.h +++ b/drivers/media/platform/rockchip/isp/dev.h @@ -290,6 +290,7 @@ struct rkisp_device { spinlock_t aiisp_lock; struct rkisp_cmsk_cfg cmsk_cfg; struct rkisp_aiisp_cfg aiisp_cfg; + struct rkisp_fpn_cfg fpn_cfg; bool is_cmsk_upd; bool is_hw_link; diff --git a/drivers/media/platform/rockchip/isp/isp_params.c b/drivers/media/platform/rockchip/isp/isp_params.c index 96d1c67e798f..4181c27acc6c 100644 --- a/drivers/media/platform/rockchip/isp/isp_params.c +++ b/drivers/media/platform/rockchip/isp/isp_params.c @@ -275,6 +275,12 @@ static void rkisp_params_vb2_stop_streaming(struct vb2_queue *vq) params_vdev->rdbk_times = 0; if (!(dev->isp_state & ISP_START)) rkisp_params_stream_stop(params_vdev); + dev->fpn_cfg.en = 0; + if (dev->fpn_cfg.buf) { + vfree(dev->fpn_cfg.buf); + dev->fpn_cfg.buf = NULL; + dev->fpn_cfg.buf_size = 0; + } } static int diff --git a/drivers/media/platform/rockchip/isp/procfs.c b/drivers/media/platform/rockchip/isp/procfs.c index d0a08a0e495c..94c983bd475f 100644 --- a/drivers/media/platform/rockchip/isp/procfs.c +++ b/drivers/media/platform/rockchip/isp/procfs.c @@ -241,6 +241,8 @@ static void isp30_show(struct rkisp_device *dev, struct seq_file *p) }; u32 val, tmp; + val = rkisp_read(dev, CSI2RX_FPN_CTRL, false); + seq_printf(p, "%-10s %s(0x%x)\n", "FPN", (val & 1) ? "ON" : "OFF", val); val = rkisp_read(dev, ISP3X_CMSK_CTRL0, false); seq_printf(p, "%-10s %s(0x%x)\n", "CMSK", (val & 1) ? "ON" : "OFF", val); val = rkisp_read(dev, ISP3X_DPCC0_MODE, false); diff --git a/drivers/media/platform/rockchip/isp/regs_v2x.h b/drivers/media/platform/rockchip/isp/regs_v2x.h index 979710b58a12..12dfdbad8449 100644 --- a/drivers/media/platform/rockchip/isp/regs_v2x.h +++ b/drivers/media/platform/rockchip/isp/regs_v2x.h @@ -561,7 +561,8 @@ #define CSI2RX_RAWFBC_EN_SHD (CSI2RX_BASE + 0x000c8) #define CSI2RX_FPN_CTRL (CSI2RX_BASE + 0x000d0) #define CSI2RX_FPN_TABLE_CTRL (CSI2RX_BASE + 0x000d4) -#define CSI2RX_FPN_TABLE_DATA (CSI2RX_BASE + 0x000d8) +#define CSI2RX_FPN_TABLE_DATA0 (CSI2RX_BASE + 0x000d8) +#define CSI2RX_FPN_TABLE_DATA1 (CSI2RX_BASE + 0x000dc) #define CSI2RX_Y_STAT_CTRL (CSI2RX_BASE + 0x000f0) #define CSI2RX_Y_STAT_RO (CSI2RX_BASE + 0x000f4) #define CSI2RX_VERSION (CSI2RX_BASE + 0x000fc) @@ -2432,6 +2433,12 @@ #define SW_CSI_ESP_IDCD_OBPIX(a) ((a) & 0x7F) #define SW_CSI_ESP_IDCD_EFPIX(a) (((a) & 0x7F) << 16) +#define SW_FPN_EN BIT(0) +#define SW_FPN_ROW_EN BIT(1) +#define SW_FPN_BITS(a) (((a) & 0x3) << 2) + +#define SW_FPN_CFG BIT(0) + #define SW_Y_STAT_INT_MODE_MASK GENMASK(3, 2) #define SW_Y_STAT_RD_FRM_ID_MASK GENMASK(5, 4) #define SW_Y_STAT_RD_TILE_ID_MASK GENMASK(7, 6) diff --git a/drivers/media/platform/rockchip/isp/rkisp.c b/drivers/media/platform/rockchip/isp/rkisp.c index 5a343bcbc5cb..256643755b71 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.c +++ b/drivers/media/platform/rockchip/isp/rkisp.c @@ -87,6 +87,7 @@ static void rkisp_config_cmsk(struct rkisp_device *dev); static void rkisp_config_aiisp(struct rkisp_device *dev); +static void rkisp_config_fpn(struct rkisp_device *dev); static inline struct rkisp_device *sd_to_isp_dev(struct v4l2_subdev *sd) { @@ -1825,6 +1826,8 @@ static int rkisp_config_isp(struct rkisp_device *dev) dev->is_aiisp_upd = dev->is_aiisp_en; rkisp_config_cmsk(dev); rkisp_config_aiisp(dev); + if (dev->hw_dev->is_single) + rkisp_config_fpn(dev); return 0; } @@ -3768,6 +3771,84 @@ static int rkisp_get_offline_raw_buf_cnt(struct rkisp_device *dev, int *cnt) return 0; } +static void rkisp_config_fpn(struct rkisp_device *dev) +{ + struct rkisp_fpn_cfg *cfg = &dev->fpn_cfg; + u32 i, val, *data; + + if (!cfg->en) { + rkisp_unite_write(dev, CSI2RX_FPN_CTRL, 0, true); + return; + } + val = SW_FPN_EN | SW_FPN_BITS(cfg->data_shift); + if (cfg->row_en) + val |= SW_FPN_ROW_EN; + rkisp_unite_write(dev, CSI2RX_FPN_CTRL, val, true); + rkisp_unite_write(dev, CSI2RX_FPN_TABLE_CTRL, SW_FPN_CFG, true); + data = cfg->buf; + /* 32bit: 8 fpn, first data line for DATA0, second line for DATA1 */ + for (i = 0; i < cfg->buf_size / 8; i++) { + val = *(data + i); + rkisp_unite_write(dev, CSI2RX_FPN_TABLE_DATA0, val, true); + val = *(data + cfg->buf_size / 8 + i); + rkisp_unite_write(dev, CSI2RX_FPN_TABLE_DATA1, val, true); + } + rkisp_unite_write(dev, CSI2RX_FPN_TABLE_CTRL, 0, true); +} + +static int rkisp_set_fpn(struct rkisp_device *dev, struct rkisp_fpn_cfg *cfg) +{ + u32 w = dev->isp_sdev.out_crop.width; + u32 h = dev->isp_sdev.out_crop.height; + int ret = 0; + + if (!cfg->en && dev->fpn_cfg.en) { + dev->fpn_cfg.en = 0; + if (dev->fpn_cfg.buf) { + vfree(dev->fpn_cfg.buf); + dev->fpn_cfg.buf = NULL; + dev->fpn_cfg.buf_size = 0; + } + return ret; + } + + if ((cfg->row_en && cfg->buf_size < h) || + (!cfg->row_en && cfg->buf_size < w)) { + dev_err(dev->dev, "fpn buf size %d row_en:%d error for %dx%d\n", + cfg->buf_size, cfg->row_en, w, h); + ret = -EINVAL; + goto err; + } + + if (dev->fpn_cfg.buf && dev->fpn_cfg.buf_size < cfg->buf_size) { + vfree(dev->fpn_cfg.buf); + dev->fpn_cfg.buf = NULL; + dev->fpn_cfg.buf_size = 0; + } + + if (!dev->fpn_cfg.buf) { + dev->fpn_cfg.buf = vmalloc(cfg->buf_size); + if (!dev->fpn_cfg.buf) { + ret = -ENOMEM; + goto err; + } + } + if (copy_from_user(dev->fpn_cfg.buf, cfg->buf, cfg->buf_size)) { + dev_err(dev->dev, "copy fpn data err\n"); + vfree(dev->fpn_cfg.buf); + dev->fpn_cfg.buf = NULL; + dev->fpn_cfg.buf_size = 0; + ret = -EFAULT; + goto err; + } + dev->fpn_cfg.en = cfg->en; + dev->fpn_cfg.row_en = cfg->row_en; + dev->fpn_cfg.data_shift = cfg->data_shift; + dev->fpn_cfg.buf_size = cfg->buf_size; +err: + return ret; +} + static long rkisp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct rkisp_device *isp_dev = sd_to_isp_dev(sd); @@ -3927,6 +4008,9 @@ static long rkisp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) case RKISP_CMD_GET_OFFLINE_RAW_BUFCNT: ret = rkisp_get_offline_raw_buf_cnt(isp_dev, arg); break; + case RKISP_CMD_SET_FPN: + ret = rkisp_set_fpn(isp_dev, arg); + break; default: ret = -ENOIOCTLCMD; } @@ -4024,6 +4108,10 @@ static long rkisp_compat_ioctl32(struct v4l2_subdev *sd, size = sizeof(int); cp_t_us = true; break; + case RKISP_CMD_SET_FPN: + size = sizeof(struct rkisp_fpn_cfg); + cp_f_us = true; + break; default: return -ENOIOCTLCMD; } diff --git a/include/uapi/linux/rk-isp2-config.h b/include/uapi/linux/rk-isp2-config.h index 2e39011b1f31..841790be482e 100644 --- a/include/uapi/linux/rk-isp2-config.h +++ b/include/uapi/linux/rk-isp2-config.h @@ -80,6 +80,9 @@ #define RKISP_CMD_GET_OFFLINE_RAW_BUFCNT \ _IOR('V', BASE_VIDIOC_PRIVATE + 22, int) +#define RKISP_CMD_SET_FPN \ + _IOW('V', BASE_VIDIOC_PRIVATE + 25, struct rkisp_fpn_cfg) + /****************ISP VIDEO IOCTL******************************/ #define RKISP_CMD_GET_CSI_MEMORY_MODE \ @@ -129,6 +132,7 @@ /* BASE_VIDIOC_PRIVATE + 115 for RKISP_CMD_GET_PARAMS_V39 */ /* BASE_VIDIOC_PRIVATE + 116 for RKISP_CMD_GET_PARAMS_V33 */ +/* BASE_VIDIOC_PRIVATE + 117 for RKISP_CMD_SET_QUICK_STREAM */ /**********************EVENT_PRIVATE***************************/ #define RKISP_V4L2_EVENT_AIISP_LINECNT (V4L2_EVENT_PRIVATE_START + 1) @@ -349,6 +353,29 @@ struct isp2x_mesh_head { __u32 data_oft; } __attribute__ ((packed)); +enum { + RKISP_FPN_DATA_SHIFT_0 = 0, + RKISP_FPN_DATA_SHIFT_1, + RKISP_FPN_DATA_SHIFT_2, + RKISP_FPN_DATA_SHIFT_3, +}; + +/* struct rkisp_aiisp_cfg + * en: enable fpn function + * row_en: row fpn mode other column fpn + * data_shift: fpn data shift, 4bits of 7bits calculate fpn data + * buf_size: buf size: row_en ? height : width + * buf: fpn data, two row or two column fpn data, 4bit one fpn data + */ +struct rkisp_fpn_cfg { + char en; + char row_en; + char data_shift; + char reserved; + int buf_size; + void *buf; +} __attribute__ ((packed)); + #define RKISP_AIISP_WR_LINECNT_ID 0 #define RKISP_AIISP_RD_LINECNT_ID 1 struct rkisp_aiisp_ev_info {