Re: [PATCH RFC] media: rockchip: rkisp1: Add support for AWB64

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Dec 30, 2024 at 10:04:36PM +0530, Jai Luthra wrote:
> On Dec 30, 2024 at 17:30:37 +0200, Laurent Pinchart wrote:
> > On Mon, Dec 30, 2024 at 12:25:09PM +0530, Jai Luthra wrote:
> > > AWB64 is an advanced auto white-balance statistics block, present on the
> > > ISP in iMX8MP. This block can calculate color statistics for a maximum
> > > of 8 different (elliptical) regions, which can be used by the AWB
> > > algorithm to better tune the color gains.
> > > 
> > > Signed-off-by: Jai Luthra <jai.luthra@xxxxxxxxxxxxxxxx>
> > > ---
> > > This patch is only compile-tested, thus marked as an RFC.
> > > 
> > > Some of the ellipse and color transformation parameters are sparsely
> > > documented, so the API might have to change on further testing.
> > > ---
> > >  .../media/platform/rockchip/rkisp1/rkisp1-common.h |   9 ++
> > >  .../media/platform/rockchip/rkisp1/rkisp1-dev.c    |   3 +-
> > >  .../media/platform/rockchip/rkisp1/rkisp1-params.c | 123 +++++++++++++++++++++
> > >  .../media/platform/rockchip/rkisp1/rkisp1-regs.h   |  41 +++++++
> > >  .../media/platform/rockchip/rkisp1/rkisp1-stats.c  |  31 +++++-
> > >  include/uapi/linux/rkisp1-config.h                 | 105 ++++++++++++++++++
> > >  6 files changed, 310 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > > index ca952fd0829ba7d923ad42fec92840ccd422b6e5..7dc9d101a1a01627f174cc4c454e4e57b38e1f8e 100644
> > > --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > > +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > > @@ -118,6 +118,7 @@ enum rkisp1_isp_pad {
> > >   * @RKISP1_FEATURE_DMA_34BIT: The ISP uses 34-bit DMA addresses
> > >   * @RKISP1_FEATURE_BLS: The ISP has a dedicated BLS block
> > >   * @RKISP1_FEATURE_COMPAND: The ISP has a companding block
> > > + * @RKISP1_FEATURE_AWB64: The ISP has an AWB64 block
> > >   *
> > >   * The ISP features are stored in a bitmask in &rkisp1_info.features and allow
> > >   * the driver to implement support for features present in some ISP versions
> > > @@ -131,6 +132,7 @@ enum rkisp1_feature {
> > >  	RKISP1_FEATURE_DMA_34BIT = BIT(4),
> > >  	RKISP1_FEATURE_BLS = BIT(5),
> > >  	RKISP1_FEATURE_COMPAND = BIT(6),
> > > +	RKISP1_FEATURE_AWB64 = BIT(7),
> > >  };
> > >  
> > >  #define rkisp1_has_feature(rkisp1, feature) \
> > > @@ -345,6 +347,8 @@ struct rkisp1_stats;
> > >  struct rkisp1_stats_ops {
> > >  	void (*get_awb_meas)(struct rkisp1_stats *stats,
> > >  			     struct rkisp1_stat_buffer *pbuf);
> > > +	void (*get_awb64_meas)(struct rkisp1_stats *stats,
> > > +			       struct rkisp1_stat_buffer *pbuf);
> > >  	void (*get_aec_meas)(struct rkisp1_stats *stats,
> > >  			     struct rkisp1_stat_buffer *pbuf);
> > >  	void (*get_hst_meas)(struct rkisp1_stats *stats,
> > > @@ -381,6 +385,11 @@ struct rkisp1_params_ops {
> > >  	void (*awb_meas_enable)(struct rkisp1_params *params,
> > >  				const struct rkisp1_cif_isp_awb_meas_config *arg,
> > >  				bool en);
> > > +	void (*awb64_meas_config)(struct rkisp1_params *params,
> > > +				  const struct rkisp1_cif_isp_awb64_meas_config *arg);
> > > +	void (*awb64_meas_enable)(struct rkisp1_params *params,
> > > +				  const struct rkisp1_cif_isp_awb64_meas_config *arg,
> > > +				  bool en);
> > >  	void (*awb_gain_config)(struct rkisp1_params *params,
> > >  				const struct rkisp1_cif_isp_awb_gain_config *arg);
> > >  	void (*aec_config)(struct rkisp1_params *params,
> > > diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> > > index 0100b9c3edbefbdc001e2e4d13049efa9493e3bd..20903823b8eec2dd6b2fda788a42ef7545158f8c 100644
> > > --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> > > +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> > > @@ -557,7 +557,8 @@ static const struct rkisp1_info imx8mp_isp_info = {
> > >  	.isp_ver = RKISP1_V_IMX8MP,
> > >  	.features = RKISP1_FEATURE_MAIN_STRIDE
> > >  		  | RKISP1_FEATURE_DMA_34BIT
> > > -		  | RKISP1_FEATURE_COMPAND,
> > > +		  | RKISP1_FEATURE_COMPAND
> > > +		  | RKISP1_FEATURE_AWB64,
> > >  	.max_width = 4096,
> > >  	.max_height = 3072,
> > >  };
> > > diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
> > > index b28f4140c8a309a3231d44d825c6461e3ecb2a44..1ee5f07d461c5ad7aadff908c25f7a5bd2ff81f9 100644
> > > --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
> > > +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
> > > @@ -60,6 +60,7 @@ union rkisp1_ext_params_config {
> > >  	struct rkisp1_ext_params_afc_config afc;
> > >  	struct rkisp1_ext_params_compand_bls_config compand_bls;
> > >  	struct rkisp1_ext_params_compand_curve_config compand_curve;
> > > +	struct rkisp1_ext_params_awb64_meas_config awb64;
> > >  };
> > >  
> > >  enum rkisp1_params_formats {
> > > @@ -674,6 +675,101 @@ rkisp1_awb_meas_enable_v12(struct rkisp1_params *params,
> > >  	}
> > >  }
> > >  
> > > +/* ISP White Balance Mode */
> > > +static void
> > > +rkisp1_awb64_meas_config_v10(struct rkisp1_params *params,
> > > +			     const struct rkisp1_cif_isp_awb64_meas_config *arg)
> > 
> > v10 refers to the Rockchip ISP v1.0. As the AWB64 block is found in the
> > VSI ISP8000 Nano (v18.02 if I'm not mistaken), which we refer to in this
> > driver as "RKISP1_V_IMX8MP", I would name this function
> > rkisp1_awb64_meas_config_imx8mp() or just rkisp1_awb64_meas_config().
> > Same for rkisp1_awb64_meas_enable_v10().
> > 
> 
> Will fix.
> 
> > > +{
> > > +	/* window offset */
> > 
> > 	/* Window offset and size */
> > 
> > > +	rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB64_V_OFFS,
> > > +		     arg->awb_wnd.v_offs);
> > > +	rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB64_V_OFFS,
> > > +		     arg->awb_wnd.v_offs);
> > 
> > You're writing the same register twice.
> > 
> 
> Oops, will fix.
> 
> > > +	/* AWB window size */
> > 
> > Drop this.
> > 
> > > +	rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB64_V_SIZE,
> > > +		     arg->awb_wnd.v_size);
> > > +	rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB64_H_SIZE,
> > > +		     arg->awb_wnd.h_size);
> > 
> > A blank line here would make code easier to read.
> > 
> > > +	/* RGB thresholds for measurement */
> > > +	rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB64_R_MIN_MAX,
> > > +		     arg->max_r << 8 | arg->min_r);
> > 
> > To simplify the calculations in the kernel, would it make sense for
> > userspace to compute this and store it in a single 16-bit field ?
> > 
> 
> Indeed, will fix.
> 
> > > +	rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB64_G_MIN_MAX,
> > > +		     arg->max_g << 8 | arg->min_g);
> > > +	rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB64_B_MIN_MAX,
> > > +		     arg->max_b << 8 | arg->min_b);
> > 
> > Same here.
> > 
> > > +	/* Minimum input divider threshold */
> > > +	rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB64_MIN_DIVIDER,
> > > +		     arg->min_div & RKISP1_CIF_ISP_AWB64_MIN_DIV_MASK);
> > 
> > And here.
> > 
> > > +	/* Colorspace matrix coefficients */
> > > +	for (int i = 0; i < 3; i++)
> > > +		for (int j = 0; j < 3; j++)
> > > +			rkisp1_write(params->rkisp1,
> > > +				     RKISP1_CIF_ISP_AWB64_CC_COEFF(i * 3 + j),
> > > +				     arg->cc_coeff[i][j]);
> > 
> > Use curly braces for outer loop.
> > 
> > > +	/* Ellipse configuration */
> > > +	for (int i = 0; i < RKISP1_CIF_ISP_AWB64_MAX_ELLIPSE; i++) {
> > 
> > 		const struct rkisp1_cif_isp_awb64_ellip *ellip = &arg->ellip[i];
> > 
> > > +		/* Center */
> > > +		rkisp1_write(params->rkisp1,
> > > +			     RKISP1_CIF_ISP_AWB64_ELLIP_CEN_X(i),
> > > +			     arg->ellip[i].cen_x &
> > > +				     RKISP1_CIF_ISP_AWB64_ELLIP_CEN_MASK);
> > 
> > 			     ellip->cen_x & RKISP1_CIF_ISP_AWB64_ELLIP_CEN_MASK);
> > 
> > Same below.
> > 
> > > +		rkisp1_write(params->rkisp1,
> > > +			     RKISP1_CIF_ISP_AWB64_ELLIP_CEN_Y(i),
> > > +			     arg->ellip[i].cen_y &
> > > +				     RKISP1_CIF_ISP_AWB64_ELLIP_CEN_MASK);
> > > +		/* Radius */
> > > +		rkisp1_write(params->rkisp1,
> > > +			     RKISP1_CIF_ISP_AWB64_ELLIP_RMAX(i),
> > > +			     arg->ellip[i].rmax &
> > > +				     RKISP1_CIF_ISP_AWB64_ELLIP_RMAX_MASK);
> > > +		/* CTM */
> > > +		rkisp1_write(params->rkisp1,
> > > +			     RKISP1_CIF_ISP_AWB64_ELLIP_A1(i),
> > > +			     arg->ellip[i].ctm[0] &
> > > +				     RKISP1_CIF_ISP_AWB64_ELLIP_A1_A3_MASK);
> > > +		rkisp1_write(params->rkisp1,
> > > +			     RKISP1_CIF_ISP_AWB64_ELLIP_A2(i),
> > > +			     arg->ellip[i].ctm[1] &
> > > +				     RKISP1_CIF_ISP_AWB64_ELLIP_A2_A4_MASK);
> > > +		rkisp1_write(params->rkisp1,
> > > +			     RKISP1_CIF_ISP_AWB64_ELLIP_A3(i),
> > > +			     arg->ellip[i].ctm[2] &
> > > +				     RKISP1_CIF_ISP_AWB64_ELLIP_A1_A3_MASK);
> > > +		rkisp1_write(params->rkisp1,
> > > +			     RKISP1_CIF_ISP_AWB64_ELLIP_A4(i),
> > > +			     arg->ellip[i].ctm[3] &
> > > +				     RKISP1_CIF_ISP_AWB64_ELLIP_A2_A4_MASK);
> > > +	}
> > > +}
> > > +
> > > +static void
> > > +rkisp1_awb64_meas_enable_v10(struct rkisp1_params *params,
> > > +			     const struct rkisp1_cif_isp_awb64_meas_config *arg,
> > > +			     bool en)
> > > +{
> > > +	u32 reg_val =
> > > +		rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB64_MEAS_MODE);
> > > +
> > > +	if (en) {
> > > +		if (arg->enable_median_filter)
> > > +			reg_val |= RKISP1_CIF_ISP_AWB64_PRE_FILTER_EN;
> > > +
> > > +		if (arg->chrom_switch)
> > > +			reg_val |= RKISP1_CIF_ISP_AWB64_CHROM_SWITCH;
> > > +
> > > +		reg_val |= (arg->ellip_unite & RKISP1_CIF_ISP_AWB64_UNITE_MASK)
> > > +			   << RKISP1_CIF_ISP_AWB64_UNITE_SHIFT;
> > 
> > You never clear any of those fields.
> 
> Ah I completely missed that, will fix.
> 
> > Is it intentional that you make it impossible to change those parameters
> > without disabling and re-enabling the block ?
> 
> I was not exactly sure what all parameters were okay to toggle 
> mid-stream, so I kept everything in the MEAS_MODE register together in 
> this routine. For now I will move everything except the module enable 
> bit to the awb64_meas_config() routine.
> 
> But I guess more experimentation from the userspace side is needed, as I 
> see in the AWB block we only allow changing the colorspace mode when 
> enabling/disabling the block, and I am not sure if similar restrictions 
> are present here.

None of the AWB64 are marked as having shadow registers, so I think
there's conceptually no difference. We should either allow programming
them all while the module is enabled, or forbid them all. I'd start by
allowing them all for now.

> > > +
> > > +		reg_val |= RKISP1_CIF_ISP_AWB64_MEAS_EN |
> > > +			   RKISP1_CIF_ISP_AWB64_IRQ_EN;
> > > +	} else {
> > > +		reg_val &= ~RKISP1_CIF_ISP_AWB64_MEAS_EN;
> > > +	}
> > > +
> > > +	rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB64_MEAS_MODE,
> > > +		     reg_val);
> > > +}
> > > +
> > >  static void
> > >  rkisp1_awb_gain_config_v10(struct rkisp1_params *params,
> > >  			   const struct rkisp1_cif_isp_awb_gain_config *arg)
> > > @@ -2005,6 +2101,25 @@ static void rkisp1_ext_params_compand_compress(struct rkisp1_params *params,
> > >  				      RKISP1_CIF_ISP_COMPAND_CTRL_COMPRESS_ENABLE);
> > >  }
> > >  
> > > +static void rkisp1_ext_params_awb64(struct rkisp1_params *params,
> > > +				    const union rkisp1_ext_params_config *block)
> > > +{
> > > +	const struct rkisp1_ext_params_awb64_meas_config *awb64 = &block->awb64;
> > > +
> > > +	if (awb64->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) {
> > > +		params->ops->awb64_meas_enable(params, &awb64->config,
> > > +					     false);
> > 
> > Wrong indentation.
> > 
> > > +		return;
> > > +	}
> > > +
> > > +	params->ops->awb64_meas_config(params, &awb64->config);
> > > +
> > > +	if ((awb64->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_ENABLE) &&
> > > +	    !(params->enabled_blocks & BIT(awb64->header.type)))
> > > +		params->ops->awb64_meas_enable(params, &awb64->config,
> > > +					     true);
> > 
> > Same here.
> > 
> > > +}
> > > +
> > >  typedef void (*rkisp1_block_handler)(struct rkisp1_params *params,
> > >  			     const union rkisp1_ext_params_config *config);
> > >  
> > > @@ -2118,6 +2233,12 @@ static const struct rkisp1_ext_params_handler {
> > >  		.group		= RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS,
> > >  		.features	= RKISP1_FEATURE_COMPAND,
> > >  	},
> > > +	[RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB64_MEAS] = {
> > > +		.size		= sizeof(struct rkisp1_ext_params_awb64_meas_config),
> > > +		.handler	= rkisp1_ext_params_awb64,
> > > +		.group		= RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS,
> > > +		.features	= RKISP1_FEATURE_AWB64,
> > > +	},
> > >  };
> > >  
> > >  static void rkisp1_ext_params_config(struct rkisp1_params *params,
> > > @@ -2381,6 +2502,8 @@ static const struct rkisp1_params_ops rkisp1_v10_params_ops = {
> > >  	.goc_config = rkisp1_goc_config_v10,
> > >  	.awb_meas_config = rkisp1_awb_meas_config_v10,
> > >  	.awb_meas_enable = rkisp1_awb_meas_enable_v10,
> > > +	.awb64_meas_config = rkisp1_awb64_meas_config_v10,
> > > +	.awb64_meas_enable = rkisp1_awb64_meas_enable_v10,
> > 
> > I think you can drop these two fields and call
> > rkisp1_awb64_meas_config() and rkisp1_awb64_meas_enable() directly.
> 
> Thanks, will do.
> 
> > >  	.awb_gain_config = rkisp1_awb_gain_config_v10,
> > >  	.aec_config = rkisp1_aec_config_v10,
> > >  	.hst_config = rkisp1_hst_config_v10,
> > > diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
> > > index bf0260600a1923eebde6b5fe233daf7d427362dd..bc292a5738198fff28715b2a7e55e26e8fbddc64 100644
> > > --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
> > > +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
> > > @@ -516,6 +516,24 @@
> > >  #define RKISP1_CIF_ISP_AWB_CBCR_MAX_REF			0x000000ff
> > >  #define RKISP1_CIF_ISP_AWB_THRES_MAX_YC			0x000000ff
> > >  
> > > +/* AWB64 */
> > > +/* ISP_AWB64_WHITE_CNT */
> > > +#define RKISP1_CIF_ISP_AWB64_GET_PIXEL_CNT(x)		((x) & 0xffffff)
> > > +/* ISP_AWB64_MEAS_MODE */
> > > +#define RKISP1_CIF_ISP_AWB64_MEAS_EN			BIT(0)
> > > +#define RKISP1_CIF_ISP_AWB64_PRE_FILTER_EN		BIT(1)
> > > +#define RKISP1_CIF_ISP_AWB64_IRQ_EN			BIT(2)
> > > +#define RKISP1_CIF_ISP_AWB64_CHROM_SWITCH		BIT(3)
> > > +#define RKISP1_CIF_ISP_AWB64_UNITE_MASK			GENMASK(5, 0)
> > > +#define RKISP1_CIF_ISP_AWB64_UNITE_SHIFT		4
> > > +/* ISP_AWB64_DIVIDER_MIN */
> > > +#define RKISP1_CIF_ISP_AWB64_MIN_DIV_MASK		GENMASK(9, 0)
> > > +/* ISP_AWB64_ELLIP */
> > > +#define RKISP1_CIF_ISP_AWB64_ELLIP_CEN_MASK		GENMASK(9, 0)
> > > +#define RKISP1_CIF_ISP_AWB64_ELLIP_A1_A3_MASK		GENMASK(11, 0)
> > > +#define RKISP1_CIF_ISP_AWB64_ELLIP_A2_A4_MASK		GENMASK(8, 0)
> > > +#define RKISP1_CIF_ISP_AWB64_ELLIP_RMAX_MASK		GENMASK(23, 0)
> > > +
> > >  /* AE */
> > >  /* ISP_EXP_CTRL */
> > >  #define RKISP1_CIF_ISP_EXP_ENA				BIT(0)
> > > @@ -1379,6 +1397,29 @@
> > >  #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x0000012c)
> > >  #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x00000130)
> > >  
> > > +#define RKISP1_CIF_ISP_AWB64_BASE		0x00002c00
> > > +#define RKISP1_CIF_ISP_AWB64_MEAS_MODE		(RKISP1_CIF_ISP_AWB64_BASE + 0x00000000)
> > > +#define RKISP1_CIF_ISP_AWB64_H_OFFS		(RKISP1_CIF_ISP_AWB64_BASE + 0x00000000)
> > > +#define RKISP1_CIF_ISP_AWB64_V_OFFS		(RKISP1_CIF_ISP_AWB64_BASE + 0x00000000)
> > > +#define RKISP1_CIF_ISP_AWB64_H_SIZE		(RKISP1_CIF_ISP_AWB64_BASE + 0x00000000)
> > > +#define RKISP1_CIF_ISP_AWB64_V_SIZE		(RKISP1_CIF_ISP_AWB64_BASE + 0x00000000)
> > > +#define RKISP1_CIF_ISP_AWB64_R_MIN_MAX		(RKISP1_CIF_ISP_AWB64_BASE + 0x00000000)
> > > +#define RKISP1_CIF_ISP_AWB64_G_MIN_MAX		(RKISP1_CIF_ISP_AWB64_BASE + 0x00000000)
> > > +#define RKISP1_CIF_ISP_AWB64_B_MIN_MAX		(RKISP1_CIF_ISP_AWB64_BASE + 0x00000000)
> > > +#define RKISP1_CIF_ISP_AWB64_MIN_DIVIDER	(RKISP1_CIF_ISP_AWB64_BASE + 0x00000000)
> > > +#define RKISP1_CIF_ISP_AWB64_CC_COEFF(n)	(RKISP1_CIF_ISP_AWB64_BASE + 0x00000000 + (n) * 4)
> > 
> > All those registers seem to be at the same address. I think the next
> > version of this patch needs to be tested.
> 
> Oops, will fix. I was testing the register writes through a separate 
> shell script. Will test the kernel driver through libcamera before 
> sending the next revision.
> 
> > > +#define RKISP1_CIF_ISP_AWB64_ELLIP_CEN_X(n)	(RKISP1_CIF_ISP_AWB64_BASE + 0x00000048 + (n) * 8)
> > > +#define RKISP1_CIF_ISP_AWB64_ELLIP_CEN_Y(n)	(RKISP1_CIF_ISP_AWB64_BASE + 0x0000004c + (n) * 8)
> > > +#define RKISP1_CIF_ISP_AWB64_ELLIP_A1(n)	(RKISP1_CIF_ISP_AWB64_BASE + 0x00000088 + (n) * 16)
> > > +#define RKISP1_CIF_ISP_AWB64_ELLIP_A2(n)	(RKISP1_CIF_ISP_AWB64_BASE + 0x0000008c + (n) * 16)
> > > +#define RKISP1_CIF_ISP_AWB64_ELLIP_A3(n)	(RKISP1_CIF_ISP_AWB64_BASE + 0x00000090 + (n) * 16)
> > > +#define RKISP1_CIF_ISP_AWB64_ELLIP_A4(n)	(RKISP1_CIF_ISP_AWB64_BASE + 0x00000094 + (n) * 16)
> > > +#define RKISP1_CIF_ISP_AWB64_ELLIP_RMAX(n)	(RKISP1_CIF_ISP_AWB64_BASE + 0x00000108 + (n) * 4)
> > > +#define RKISP1_CIF_ISP_AWB64_WHITE_CNT(n)	(RKISP1_CIF_ISP_AWB64_BASE + 0x00000128 + (n) * 4)
> > > +#define RKISP1_CIF_ISP_AWB64_R_ACCU(n)		(RKISP1_CIF_ISP_AWB64_BASE + 0x00000148 + (n) * 12)
> > > +#define RKISP1_CIF_ISP_AWB64_G_ACCU(n)		(RKISP1_CIF_ISP_AWB64_BASE + 0x0000014c + (n) * 12)
> > > +#define RKISP1_CIF_ISP_AWB64_B_ACCU(n)		(RKISP1_CIF_ISP_AWB64_BASE + 0x00000150 + (n) * 12)
> > > +
> > >  #define RKISP1_CIF_ISP_HIST_BASE_V12		0x00002c00
> > >  #define RKISP1_CIF_ISP_HIST_CTRL_V12		(RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000000)
> > >  #define RKISP1_CIF_ISP_HIST_SIZE_V12		(RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000004)
> > > diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c
> > > index d5fdb8f82dc78b0143f71d76f36817db389921b7..a5b82963e74dac2340a1b3b07cd8d99dd23b5d5d 100644
> > > --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c
> > > +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c
> > > @@ -172,6 +172,31 @@ rkisp1_stats_init_vb2_queue(struct vb2_queue *q, struct rkisp1_stats *stats)
> > >  	return vb2_queue_init(q);
> > >  }
> > >  
> > > +static void rkisp1_stats_get_awb64_meas_v10(struct rkisp1_stats *stats,
> > > +					    struct rkisp1_stat_buffer *pbuf)
> > > +{
> > > +	/* Protect against concurrent access from ISR? */
> > 
> > If this is needed, let's address the issue. If it's not, let's drop the
> > comment.
> 
> Ack. I don't yet know if the same interrupt bit is used to signal stats 
> ready for both AWB and AWB64 blocks. Will hopefully have a better idea 
> once testing this with userspace.
> 
> > > +	struct rkisp1_device *rkisp1 = stats->rkisp1;
> > > +	unsigned int i;
> > > +	u32 white_cnt;
> > > +
> > > +	pbuf->meas_type |= RKISP1_CIF_ISP_STAT_AWB64;
> > > +
> > > +	for (i = 0; i < RKISP1_CIF_ISP_AWB64_MAX_ELLIPSE; i++) {
> > 
> > 	for (unsigned int i = 0; i < RKISP1_CIF_ISP_AWB64_MAX_ELLIPSE; i++) {
> > 		struct rkisp1_cif_isp_awb64_meas *count =
> > 			&pbuf->params.awb64.count[i];
> > 
> > and use count below.
> > 
> > > +		white_cnt = rkisp1_read(rkisp1,
> > > +					RKISP1_CIF_ISP_AWB64_WHITE_CNT(i));
> > > +		pbuf->params.awb64.count[i].cnt =
> > > +			RKISP1_CIF_ISP_AWB64_GET_PIXEL_CNT(white_cnt);
> > > +
> > > +		pbuf->params.awb64.count[i].accu_cr_or_r =
> > > +			rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB64_R_ACCU(i));
> > > +		pbuf->params.awb64.count[i].accu_y_or_g =
> > > +			rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB64_G_ACCU(i));
> > > +		pbuf->params.awb64.count[i].accu_cb_or_b =
> > > +			rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB64_B_ACCU(i));
> > > +	}
> > > +}
> > > +
> > >  static void rkisp1_stats_get_awb_meas_v10(struct rkisp1_stats *stats,
> > >  					  struct rkisp1_stat_buffer *pbuf)
> > >  {
> > > @@ -325,6 +350,7 @@ static void rkisp1_stats_get_bls_meas(struct rkisp1_stats *stats,
> > >  
> > >  static const struct rkisp1_stats_ops rkisp1_v10_stats_ops = {
> > >  	.get_awb_meas = rkisp1_stats_get_awb_meas_v10,
> > > +	.get_awb64_meas = rkisp1_stats_get_awb64_meas_v10,
> > 
> > Not all ISP versions using rkisp1_v10_stats_ops support the AWB64 block.
> > You need to duplicate this structure, with a specific version for the
> > i.MX8MP.
> > 
> > >  	.get_aec_meas = rkisp1_stats_get_aec_meas_v10,
> > >  	.get_hst_meas = rkisp1_stats_get_hst_meas_v10,
> > >  };
> > > @@ -355,8 +381,11 @@ rkisp1_stats_send_measurement(struct rkisp1_stats *stats, u32 isp_ris)
> > >  
> > >  	cur_stat_buf = (struct rkisp1_stat_buffer *)
> > >  			vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0);
> > > -	if (isp_ris & RKISP1_CIF_ISP_AWB_DONE)
> > > +	if (isp_ris & RKISP1_CIF_ISP_AWB_DONE) {
> > >  		stats->ops->get_awb_meas(stats, cur_stat_buf);
> > > +		if (stats->ops->get_awb64_meas)
> > > +			stats->ops->get_awb64_meas(stats, cur_stat_buf);
> > 
> > As you need to create rkisp1_imx8mp_stats_ops as explained above, you
> > can combine awb and awb64 support in the .get_awb_meas() operation. One
> > option is to create a rkisp1_stats_get_awb_meas_imx8mp() that calls
> > rkisp1_stats_get_awb_meas_v10() and rkisp1_stats_get_awb64_meas().
> 
> Makes sense, will fix.
> 
> > > +	}
> > >  
> > >  	if (isp_ris & RKISP1_CIF_ISP_AFM_FIN)
> > >  		rkisp1_stats_get_afc_meas(stats, cur_stat_buf);
> > > diff --git a/include/uapi/linux/rkisp1-config.h b/include/uapi/linux/rkisp1-config.h
> > > index 430daceafac7056951be968f3b4d9cd50eb04e71..22243ab8e079925d58f739b3078efed04fd8acda 100644
> > > --- a/include/uapi/linux/rkisp1-config.h
> > > +++ b/include/uapi/linux/rkisp1-config.h
> > > @@ -45,6 +45,8 @@
> > >  #define RKISP1_CIF_ISP_MODULE_DPF		(1U << 16)
> > >  /* Denoise Pre-Filter Strength */
> > >  #define RKISP1_CIF_ISP_MODULE_DPF_STRENGTH	(1U << 17)
> > > +/* Auto White Balancing 64 statistics configuration */
> > > +#define RKISP1_CIF_ISP_MODULE_AWB64		(1U << 18)
> > 
> > This doesn't seem to be used, is that expected ?
> 
> Ah I don't think this is needed for blocks that are only used with 
> extended params API. Will drop after double checking.
> 
> > >  
> > >  #define RKISP1_CIF_ISP_CTK_COEFF_MAX            0x100
> > >  #define RKISP1_CIF_ISP_CTK_OFFSET_MAX           0x800
> > > @@ -88,6 +90,11 @@
> > >  #define RKISP1_CIF_ISP_AWB_MAX_GRID                1
> > >  #define RKISP1_CIF_ISP_AWB_MAX_FRAMES              7
> > >  
> > > +/*
> > > + * Automatic white balance extended block (AWB64)
> > > + */
> > > +#define RKISP1_CIF_ISP_AWB64_MAX_ELLIPSE           8
> > > +
> > >  /*
> > >   * Gamma out
> > >   */
> > > @@ -176,6 +183,7 @@
> > >  #define RKISP1_CIF_ISP_STAT_AUTOEXP       (1U << 1)
> > >  #define RKISP1_CIF_ISP_STAT_AFM           (1U << 2)
> > >  #define RKISP1_CIF_ISP_STAT_HIST          (1U << 3)
> > > +#define RKISP1_CIF_ISP_STAT_AWB64         (1U << 4)
> > >  
> > >  /**
> > >   * enum rkisp1_cif_isp_version - ISP variants
> > > @@ -519,6 +527,55 @@ struct rkisp1_cif_isp_awb_gain_config {
> > >  	__u16 gain_green_b;
> > >  };
> > >  
> > > +/**
> > > + * struct rkisp1_cif_isp_awb64_ellipse - Ellipse configuration for AWB64 measurement
> > > + *
> > > + * @rmax: Points within rmax (24 bits) distance from center are considered white point
> > 
> > What's the unit ? A maximum radius of 16M pixels doesn't seem to make
> > sense. Is this the square of the maximum radius ? Or a fixed-point
> > integer value with a decimal part ?
> 
> The documentation just says 24 bits for RMax. My guess is it might be 
> some fixed point integer value, but I will have to experiment more to be 
> sure.
> 
> Same case for the color conversion and ellipse CTM co-efficients. Those 
> are most likely fixed point, but the documentation does not mention 
> that, and if it is how many bits are the fractional part.

Experimentation is needed. The reason why I mentioned the square of the
maximum radius is that it's easier to compute the square of euclidian
distances in hardware than the distance itself. It's just a guess
though, there may be an optimized way to perform the calculation in the
ISP that would use the distance for comparison.

Could you design a test procedure to try and understand the different
parameters ? We can then discuss how to implement it.

> > > + * @cen_x: X co-ordinate of the center of ellipse (10 bits)
> > 
> > s/co-ordinate/coordinate/
> > 
> > Same below.
> > 
> > > + * @cen_y: Y co-ordinate of the center of ellipse (10 bits)
> > > + * @ctm: Co-ordinate transformation matrix
> > > + *       ctm[0] and ctm[2] are 12 bits, ctm[1] and ctm[3] are 9 bits
> > > + */
> > > +struct rkisp1_cif_isp_awb64_ellip {
> > > +	__u32 rmax;
> > > +	__u16 cen_x;
> > > +	__u16 cen_y;
> > > +	__u16 ctm[4];
> > > +};
> > > +
> > > +/**
> > > + * struct rkisp1_cif_isp_awb64_meas_config - Configuration for the AWB64 stats
> > > + *
> > > + * @awb_wnd: White balance measurement window (in pixels)
> > > + * @ellip: Ellipse regions used for measurement
> > > + * @cc_coeff: Colorspace matrix (all coefficients are 11 bits)
> > > + * @min_div: Minimum divider, if input is less than this don't do division (10 bits)
> > > + * @max_r: Only pixels with R < max_r contribute to measurement
> > > + * @min_r: Only pixels with R > min_r contribute to measurement
> > > + * @max_g: Only pixels with G < max_g contribute to measurement
> > > + * @min_g: Only pixels with G > min_g contribute to measurement
> > > + * @max_b: Only pixels with B < max_b contribute to measurement
> > > + * @min_b: Only pixels with B > min_b contribute to measurement
> > > + * @ellip_unite: Bitmask to select which regions should be combined for measurement
> > > + *               bits 0:2 to combine ellipse 0 with ellipse 1,2,3
> > > + *               bits 3:5 to combine ellipse 4 with ellipse 5,6,7
> > > + */
> > > +struct rkisp1_cif_isp_awb64_meas_config {
> > > +	struct rkisp1_cif_isp_window awb_wnd;
> > > +	struct rkisp1_cif_isp_awb64_ellip ellip[RKISP1_CIF_ISP_AWB64_MAX_ELLIPSE];
> > > +	__u16 cc_coeff[3][3];
> > > +	__u16 min_div;
> > > +	__u8 max_r;
> > > +	__u8 min_r;
> > > +	__u8 max_g;
> > > +	__u8 min_g;
> > > +	__u8 max_b;
> > > +	__u8 min_b;
> > > +	__u8 enable_median_filter;
> > 
> > This field is not documented.
> > 
> > > +	__u8 ellip_unite;
> > > +	__u8 chrom_switch;
> > 
> > Same here. Please compile-test the documentation.
> 
> Will do.
> 
> > > +};
> > > +
> > >  /**
> > >   * struct rkisp1_cif_isp_flt_config - Configuration used by ISP filtering
> > >   *
> > > @@ -1006,6 +1063,34 @@ struct rkisp1_cif_isp_hist_stat {
> > >  	__u32 hist_bins[RKISP1_CIF_ISP_HIST_BIN_N_MAX];
> > >  };
> > >  
> > > +/**
> > > + * struct rkisp1_cif_isp_awb64_meas - AWB64 measured values
> > > + *
> > > + * @cnt: White pixel count, number of "white pixels" found during last
> > > + *	 measurement
> > > + * @accu_y_or_g: Total value of Y within elliptical region,
> > > + *		 Green if RGB is selected.
> > > + * @accu_cb_or_b: Total value of Cb within elliptical region,
> > > + *		  Blue if RGB is selected.
> > > + * @accu_cr_or_r: Total value of Cr within elliptical region,
> > > + *		  Red if RGB is selected.
> > > + */
> > > +struct rkisp1_cif_isp_awb64_meas {
> > > +	__u32 cnt;
> > > +	__u32 accu_y_or_g;
> > > +	__u32 accu_cb_or_b;
> > > +	__u32 accu_cr_or_r;
> > > +};
> > > +
> > > +/**
> > > + * struct rkisp1_cif_isp_awb64_stat - statistics AWB64 data
> > > + *
> > > + * @count: Measured pixel accumulator data for elliptical regions
> > > + */
> > > +struct rkisp1_cif_isp_awb64_stat {
> > > +	struct rkisp1_cif_isp_awb64_meas count[RKISP1_CIF_ISP_AWB64_MAX_ELLIPSE];
> > > +};
> > > +
> > >  /**
> > >   * struct rkisp1_cif_isp_stat - Rockchip ISP1 Statistics Data
> > >   *
> > > @@ -1019,6 +1104,7 @@ struct rkisp1_cif_isp_stat {
> > >  	struct rkisp1_cif_isp_ae_stat ae;
> > >  	struct rkisp1_cif_isp_af_stat af;
> > >  	struct rkisp1_cif_isp_hist_stat hist;
> > > +	struct rkisp1_cif_isp_awb64_stat awb64;
> > >  };
> > >  
> > >  /**
> > > @@ -1059,6 +1145,7 @@ struct rkisp1_stat_buffer {
> > >   * @RKISP1_EXT_PARAMS_BLOCK_TYPE_COMPAND_BLS: BLS in the compand block
> > >   * @RKISP1_EXT_PARAMS_BLOCK_TYPE_COMPAND_EXPAND: Companding expand curve
> > >   * @RKISP1_EXT_PARAMS_BLOCK_TYPE_COMPAND_COMPRESS: Companding compress curve
> > > + * @RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB64_MEAS: Auto white balance 64 statistics
> > >   */
> > >  enum rkisp1_ext_params_block_type {
> > >  	RKISP1_EXT_PARAMS_BLOCK_TYPE_BLS,
> > > @@ -1081,6 +1168,7 @@ enum rkisp1_ext_params_block_type {
> > >  	RKISP1_EXT_PARAMS_BLOCK_TYPE_COMPAND_BLS,
> > >  	RKISP1_EXT_PARAMS_BLOCK_TYPE_COMPAND_EXPAND,
> > >  	RKISP1_EXT_PARAMS_BLOCK_TYPE_COMPAND_COMPRESS,
> > > +	RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB64_MEAS,
> > >  };
> > >  
> > >  #define RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE	(1U << 0)
> > > @@ -1376,6 +1464,23 @@ struct rkisp1_ext_params_awb_meas_config {
> > >  	struct rkisp1_cif_isp_awb_meas_config config;
> > >  } __attribute__((aligned(8)));
> > >  
> > > +/**
> > > + * struct rkisp1_ext_params_awb64_meas_config - RkISP1 extensible params AWB64
> > > + *						Meas config
> > > + *
> > > + * RkISP1 extensible parameters Auto-White Balance 64 Measurement configuration
> > > + * block. Identified by :c:type:`RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB64_MEAS`.
> > > + *
> > > + * @header: The RkISP1 extensible parameters header, see
> > > + *	    :c:type:`rkisp1_ext_params_block_header`
> > > + * @config: Auto-White Balance 64 measure configuration, see
> > > + *	    :c:type:`rkisp1_cif_isp_awb64_meas_config`
> > > + */
> > > +struct rkisp1_ext_params_awb64_meas_config {
> > > +	struct rkisp1_ext_params_block_header header;
> > > +	struct rkisp1_cif_isp_awb64_meas_config config;
> > > +} __attribute__((aligned(8)));
> > > +
> > >  /**
> > >   * struct rkisp1_ext_params_hst_config - RkISP1 extensible params Histogram config
> > >   *
> > > 
> > > ---
> > > base-commit: 40384c840ea1944d7c5a392e8975ed088ecf0b37
> > > change-id: 20241230-awb64-79270098e15e
> 
> Will fix all the whitespace/indent issues that I didn't explictly ack 
> above.

-- 
Regards,

Laurent Pinchart




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux