diff --git a/drivers/media/platform/rockchip/isp/csi.c b/drivers/media/platform/rockchip/isp/csi.c index 3b55fcfc3272..7f60a81b2810 100644 --- a/drivers/media/platform/rockchip/isp/csi.c +++ b/drivers/media/platform/rockchip/isp/csi.c @@ -429,6 +429,108 @@ static int csi_config(struct rkisp_csi_device *csi) return 0; } +int rkisp_expander_config(struct rkisp_device *dev, + struct rkmodule_hdr_cfg *cfg, bool on) +{ + struct rkmodule_hdr_cfg hdr_cfg; + int ret = -EINVAL; + u32 i, val, num, d0, d1, drop_bit = 0; + + if (dev->isp_ver != ISP_V32) + return 0; + + if (!on) { + rkisp_write(dev, ISP32_EXPD_CTRL, 0, false); + return 0; + } + + if (!cfg) { + struct v4l2_subdev *sd = NULL; + + get_remote_mipi_sensor(dev, &sd, MEDIA_ENT_F_PROC_VIDEO_COMPOSER); + if (!sd) + goto err; + ret = v4l2_subdev_call(sd, core, ioctl, RKMODULE_GET_HDR_CFG, &hdr_cfg); + if (ret) + goto err; + cfg = &hdr_cfg; + } + + if (cfg->hdr_mode != HDR_COMPR) + return 0; + + /* compressed data max 12bit and src data max 20bit */ + if (cfg->compr.bit > 20) + drop_bit = cfg->compr.bit - 20; + dev->hdr.compr_bit = cfg->compr.bit - drop_bit; + + num = cfg->compr.segment; + for (i = 0; i < num; i++) { + val = cfg->compr.slope_k[i]; + rkisp_write(dev, ISP32_EXPD_K0 + i * 4, val, false); + } + + d0 = 0; + d1 = cfg->compr.data_compr[0]; + val = ISP32_EXPD_DATA(d0, d1 > 0xfff ? 0xfff : d1); + rkisp_write(dev, ISP32_EXPD_X00_01, val, false); + + d1 = cfg->compr.data_src_shitf[0]; + val = ISP32_EXPD_DATA(d0, drop_bit ? d1 >> drop_bit : d1); + rkisp_write(dev, ISP32_EXPD_Y00_01, val, false); + + for (i = 1; i < num - 1; i += 2) { + d0 = cfg->compr.data_compr[i]; + d1 = cfg->compr.data_compr[i + 1]; + val = ISP32_EXPD_DATA(d0 > 0xfff ? 0xfff : d0, + d1 > 0xfff ? 0xfff : d1); + rkisp_write(dev, ISP32_EXPD_X00_01 + (i + 1) * 2, val, false); + + d0 = cfg->compr.data_src_shitf[i]; + d1 = cfg->compr.data_src_shitf[i + 1]; + if (drop_bit) { + d0 = d0 >> drop_bit; + d1 = d1 >> drop_bit; + } + val = ISP32_EXPD_DATA(d0, d1); + rkisp_write(dev, ISP32_EXPD_Y00_01 + (i + 1) * 2, val, false); + } + + /* the last valid point */ + val = cfg->compr.data_compr[i]; + val = val > 0xfff ? 0xfff : val; + d0 = ISP32_EXPD_DATA(val, val); + + val = cfg->compr.data_src_shitf[i]; + val = drop_bit ? val >> drop_bit : val; + d1 = ISP32_EXPD_DATA(val, val); + + num = HDR_COMPR_SEGMENT_16; + for (; i < num - 1; i += 2) { + rkisp_write(dev, ISP32_EXPD_X00_01 + (i + 1) * 2, d0, false); + rkisp_write(dev, ISP32_EXPD_Y00_01 + (i + 1) * 2, d1, false); + } + rkisp_write(dev, ISP32_EXPD_Y16, val, false); + + switch (cfg->compr.segment) { + case HDR_COMPR_SEGMENT_12: + num = 1; + break; + case HDR_COMPR_SEGMENT_16: + num = 2; + break; + default: + num = 0; + } + val = ISP32_EXPD_EN | + ISP32_EXPD_MODE(num) | + ISP32_EXPD_K_SHIFT(cfg->compr.k_shift); + rkisp_write(dev, ISP32_EXPD_CTRL, val, false); + return 0; +err: + return -EINVAL; +} + int rkisp_csi_config_patch(struct rkisp_device *dev) { int val = 0, ret = 0; @@ -458,11 +560,12 @@ int rkisp_csi_config_patch(struct rkisp_device *dev) if (!ret) { dev->hdr.op_mode = hdr_cfg.hdr_mode; dev->hdr.esp_mode = hdr_cfg.esp.mode; + rkisp_expander_config(dev, &hdr_cfg, true); } } - /* normal read back mode for V2X */ - if (dev->hdr.op_mode == HDR_NORMAL) + /* normal read back mode default */ + if (dev->hdr.op_mode == HDR_NORMAL || dev->hdr.op_mode == HDR_COMPR) dev->hdr.op_mode = HDR_RDBK_FRAME1; if (dev->isp_inp == INP_CIF && dev->hw_dev->is_single) diff --git a/drivers/media/platform/rockchip/isp/dev.h b/drivers/media/platform/rockchip/isp/dev.h index 6763ab4a70d6..e30b545f5fb6 100644 --- a/drivers/media/platform/rockchip/isp/dev.h +++ b/drivers/media/platform/rockchip/isp/dev.h @@ -149,6 +149,7 @@ struct rkisp_sensor_info { struct rkisp_hdr { u8 op_mode; u8 esp_mode; + u8 compr_bit; u8 index[HDR_DMA_MAX]; atomic_t refcnt; struct v4l2_subdev *sensor; diff --git a/drivers/media/platform/rockchip/isp/regs_v3x.h b/drivers/media/platform/rockchip/isp/regs_v3x.h index 5a1fb5ec0227..390ae828aec0 100644 --- a/drivers/media/platform/rockchip/isp/regs_v3x.h +++ b/drivers/media/platform/rockchip/isp/regs_v3x.h @@ -966,6 +966,42 @@ #define ISP32_BLS_ISP_OB_PREDGAIN (ISP3X_BLS_BASE + 0x0006c) #define ISP32_BLS_ISP_OB_MAX (ISP3X_BLS_BASE + 0x00070) +#define ISP32_EXPD_BASE 0x00003200 +#define ISP32_EXPD_CTRL (ISP32_EXPD_BASE + 0x00000) +#define ISP32_EXPD_X00_01 (ISP32_EXPD_BASE + 0x00004) +#define ISP32_EXPD_X02_03 (ISP32_EXPD_BASE + 0x00008) +#define ISP32_EXPD_X04_05 (ISP32_EXPD_BASE + 0x0000C) +#define ISP32_EXPD_X06_07 (ISP32_EXPD_BASE + 0x00010) +#define ISP32_EXPD_X08_09 (ISP32_EXPD_BASE + 0x00014) +#define ISP32_EXPD_X10_11 (ISP32_EXPD_BASE + 0x00018) +#define ISP32_EXPD_X12_13 (ISP32_EXPD_BASE + 0x0001C) +#define ISP32_EXPD_X14_15 (ISP32_EXPD_BASE + 0x00020) +#define ISP32_EXPD_Y00_01 (ISP32_EXPD_BASE + 0x00024) +#define ISP32_EXPD_Y02_03 (ISP32_EXPD_BASE + 0x00028) +#define ISP32_EXPD_Y04_05 (ISP32_EXPD_BASE + 0x0002C) +#define ISP32_EXPD_Y06_07 (ISP32_EXPD_BASE + 0x00030) +#define ISP32_EXPD_Y08_09 (ISP32_EXPD_BASE + 0x00034) +#define ISP32_EXPD_Y10_11 (ISP32_EXPD_BASE + 0x00038) +#define ISP32_EXPD_Y12_13 (ISP32_EXPD_BASE + 0x0003C) +#define ISP32_EXPD_Y14_15 (ISP32_EXPD_BASE + 0x00040) +#define ISP32_EXPD_Y16 (ISP32_EXPD_BASE + 0x00044) +#define ISP32_EXPD_K0 (ISP32_EXPD_BASE + 0x00048) +#define ISP32_EXPD_K1 (ISP32_EXPD_BASE + 0x0004c) +#define ISP32_EXPD_K2 (ISP32_EXPD_BASE + 0x00050) +#define ISP32_EXPD_K3 (ISP32_EXPD_BASE + 0x00054) +#define ISP32_EXPD_K4 (ISP32_EXPD_BASE + 0x00058) +#define ISP32_EXPD_K5 (ISP32_EXPD_BASE + 0x0005C) +#define ISP32_EXPD_K6 (ISP32_EXPD_BASE + 0x00060) +#define ISP32_EXPD_K7 (ISP32_EXPD_BASE + 0x00064) +#define ISP32_EXPD_K8 (ISP32_EXPD_BASE + 0x00068) +#define ISP32_EXPD_K9 (ISP32_EXPD_BASE + 0x0006C) +#define ISP32_EXPD_K10 (ISP32_EXPD_BASE + 0x00070) +#define ISP32_EXPD_K11 (ISP32_EXPD_BASE + 0x00074) +#define ISP32_EXPD_K12 (ISP32_EXPD_BASE + 0x00078) +#define ISP32_EXPD_K13 (ISP32_EXPD_BASE + 0x0007C) +#define ISP32_EXPD_K14 (ISP32_EXPD_BASE + 0x00080) +#define ISP32_EXPD_K15 (ISP32_EXPD_BASE + 0x00084) + #define ISP3X_DPCC0_BASE 0x00003400 #define ISP3X_DPCC1_BASE 0x00003500 #define ISP3X_DPCC2_BASE 0x00003600 @@ -2044,6 +2080,13 @@ /* RAWNR */ +/* EXPD */ +#define ISP32_EXPD_EN BIT(0) +#define ISP32_EXPD_K_SHIFT(a) (((a) & 0xf) << 4) +#define ISP32_EXPD_MODE(a) (((a) & 0x3) << 8) + +#define ISP32_EXPD_DATA(a, b) ((a) | (b) << 16) + /* DPCC */ /* CCM */ diff --git a/drivers/media/platform/rockchip/isp/rkisp.c b/drivers/media/platform/rockchip/isp/rkisp.c index 0d07e7cf4e10..f925a7564728 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.c +++ b/drivers/media/platform/rockchip/isp/rkisp.c @@ -517,7 +517,7 @@ void rkisp_trigger_read_back(struct rkisp_device *dev, u8 dma2frm, u32 mode, boo rkisp_dmarx_get_frame(dev, &cur_frame_id, NULL, NULL, true); val = 0; - if (mode & T_START_X1) { + if (mode & (T_START_X1 | T_START_C)) { rd_mode = HDR_RDBK_FRAME1; } else if (mode & T_START_X2) { rd_mode = HDR_RDBK_FRAME2; @@ -530,6 +530,11 @@ void rkisp_trigger_read_back(struct rkisp_device *dev, u8 dma2frm, u32 mode, boo val = rkisp_read(dev, ISP_HDRMGE_BASE, false) & 0xf; } + if (mode & T_START_C) + rkisp_expander_config(dev, NULL, true); + else + rkisp_expander_config(dev, NULL, false); + if (is_feature_on) { if ((ISP2X_MODULE_HDRMGE & ~iq_feature) && (val & SW_HDRMGE_EN)) { v4l2_err(&dev->v4l2_dev, "hdrmge is not supported\n"); diff --git a/drivers/media/platform/rockchip/isp/rkisp.h b/drivers/media/platform/rockchip/isp/rkisp.h index 97f433c0ac23..a4e5b84e58a1 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.h +++ b/drivers/media/platform/rockchip/isp/rkisp.h @@ -178,6 +178,9 @@ int rkisp_rdbk_trigger_event(struct rkisp_device *dev, u32 cmd, void *arg); void rkisp_rx_buf_pool_free(struct rkisp_device *dev); +int rkisp_expander_config(struct rkisp_device *dev, + struct rkmodule_hdr_cfg *cfg, bool on); + static inline struct ispsd_out_fmt *rkisp_get_ispsd_out_fmt(struct rkisp_isp_subdev *isp_sdev) { diff --git a/include/uapi/linux/rk-camera-module.h b/include/uapi/linux/rk-camera-module.h index a2637b73a2cb..16fe2c78c454 100644 --- a/include/uapi/linux/rk-camera-module.h +++ b/include/uapi/linux/rk-camera-module.h @@ -352,11 +352,38 @@ struct rkmodule_lsc_cfg { * NO_HDR: linear mode * HDR_X2: hdr two frame or line mode * HDR_X3: hdr three or line mode + * HDR_COMPR: linearised and compressed data for hdr */ enum rkmodule_hdr_mode { NO_HDR = 0, HDR_X2 = 5, HDR_X3 = 6, + HDR_COMPR, +}; + +enum rkmodule_hdr_compr_segment { + HDR_COMPR_SEGMENT_4 = 4, + HDR_COMPR_SEGMENT_12 = 12, + HDR_COMPR_SEGMENT_16 = 16, +}; + +/* rkmodule_hdr_compr + * linearised and compressed data for hdr: data_src = K * data_compr + XX + * + * bit: bit of src data, max 20 bit. + * segment: linear segment, support 4, 6 or 16. + * k_shift: left shift bit of slop amplification factor, 2^k_shift, [0 15]. + * slope_k: K * 2^k_shift. + * data_src_shitf: left shift bit of source data, data_src = 2^data_src_shitf + * data_compr: compressed data. + */ +struct rkmodule_hdr_compr { + enum rkmodule_hdr_compr_segment segment; + __u8 bit; + __u8 k_shift; + __u8 data_src_shitf[HDR_COMPR_SEGMENT_16]; + __u16 data_compr[HDR_COMPR_SEGMENT_16]; + __u32 slope_k[HDR_COMPR_SEGMENT_16]; }; /** @@ -395,6 +422,7 @@ struct rkmodule_hdr_esp { struct rkmodule_hdr_cfg { __u32 hdr_mode; struct rkmodule_hdr_esp esp; + struct rkmodule_hdr_compr compr; } __attribute__ ((packed)); /* sensor lvds sync code diff --git a/include/uapi/linux/rkisp2-config.h b/include/uapi/linux/rkisp2-config.h index c7b28cf75c33..456d37c93233 100644 --- a/include/uapi/linux/rkisp2-config.h +++ b/include/uapi/linux/rkisp2-config.h @@ -334,6 +334,7 @@ struct rkisp_mirror_flip { * T_START_X1: isp read one frame * T_START_X2: isp read hdr two frame * T_START_X3: isp read hdr three frame + * T_START_C: isp read hdr linearised and compressed data */ enum isp2x_trigger_mode { T_TRY = BIT(0), @@ -343,6 +344,7 @@ enum isp2x_trigger_mode { T_START_X1 = BIT(4), T_START_X2 = BIT(5), T_START_X3 = BIT(6), + T_START_C = BIT(7), }; struct isp2x_csi_trigger {