diff options
| author | Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> | 2026-07-30 19:12:35 +0200 |
|---|---|---|
| committer | Sakari Ailus <sakari.ailus@linux.intel.com> | 2026-07-30 20:51:35 +0300 |
| commit | b020bec416932aa923739df7d2f2b37b85cfd318 (patch) | |
| tree | 881d0e2da754d160cba9ebff05537a2193a8ed19 /drivers | |
| parent | 9ebf50010c686f77ff403d07548a8ad678184f2a (diff) | |
| download | linux-stable-b020bec416932aa923739df7d2f2b37b85cfd318.tar.gz linux-stable-b020bec416932aa923739df7d2f2b37b85cfd318.zip | |
media: rppx1: exm: Add support for exposure measurement
Extend the RPPX1 driver to allow setting the exposure measurement
configuration and consuming the resulting statistics. It uses the RPPX1
framework for parameters and its writer abstraction to allow the user to
control how, and when, configuration is applied to the RPPX1.
Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Co-developed-by: Jai Luthra <jai.luthra+renesas@ideasonboard.com>
Signed-off-by: Jai Luthra <jai.luthra+renesas@ideasonboard.com>
Co-developed-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Diffstat (limited to 'drivers')
4 files changed, 93 insertions, 0 deletions
diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_module.h b/drivers/media/platform/dreamchip/rppx1/rpp_module.h index 0e36b717b4ef..e968ec67b9f5 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_module.h +++ b/drivers/media/platform/dreamchip/rppx1/rpp_module.h @@ -48,11 +48,13 @@ void rpp_module_clrset(struct rpp_module *mod, u32 offset, u32 mask, u32 value); union rppx1_params_block { struct v4l2_isp_block_header header; struct rppx1_awbg_params awbg; + struct rppx1_exm_params exm; struct rppx1_wbmeas_params wbmeas; }; union rppx1_stats_block { struct v4l2_isp_block_header header; + struct rppx1_exm_stats exm; struct rppx1_wbmeas_stats wbmeas; }; diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/media/platform/dreamchip/rppx1/rpp_params.c index 17bbcf366970..8c0f45e8066a 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_params.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -19,6 +19,8 @@ static const struct v4l2_isp_params_block_type_info rppx1_ext_params_blocks_info[] = { RPPX1_PARAMS_BLOCK_INFO(AWBG_PRE1, awbg), RPPX1_PARAMS_BLOCK_INFO(AWBG_PRE2, awbg), + RPPX1_PARAMS_BLOCK_INFO(EXM_PRE1, exm), + RPPX1_PARAMS_BLOCK_INFO(EXM_PRE2, exm), RPPX1_PARAMS_BLOCK_INFO(WBMEAS_POST, wbmeas), }; @@ -56,6 +58,9 @@ int rppx1_params(struct rppx1 *rpp, struct vb2_buffer *vb, size_t max_size, case RPPX1_PARAMS_BLOCK_TYPE_AWBG_PRE1: module = &rpp->pre1.awbg; break; + case RPPX1_PARAMS_BLOCK_TYPE_EXM_PRE1: + module = &rpp->pre1.exm; + break; case RPPX1_PARAMS_BLOCK_TYPE_WBMEAS_POST: module = &rpp->post.wbmeas; break; diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c b/drivers/media/platform/dreamchip/rppx1/rpp_stats.c index c99ea158abcf..388c758d805d 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_stats.c @@ -17,6 +17,7 @@ static const struct v4l2_isp_stats_block_type_info rppx1_stats_blocks_info[] = { + RPPX1_STATS_BLOCK_INFO(EXM_PRE1, exm), RPPX1_STATS_BLOCK_INFO(WBMEAS_POST, wbmeas), }; @@ -34,6 +35,15 @@ void rppx1_stats_fill_isr(struct rppx1 *rpp, u32 isc, void *buf) v4l2_isp_stats_init_buffer(stats, V4L2_ISP_VERSION_V1); + if (isc & RPPX1_IRQ_ID_PRE1_EXM) { + block = rppx1_init_stats_block(rpp, stats, + RPPX1_STATS_BLOCK_TYPE_EXM_PRE1); + if (IS_ERR(block)) + return; + + rpp_module_call(&rpp->pre1.exm, fill_stats, block); + } + if (isc & RPPX1_IRQ_ID_POST_AWB_MEAS) { block = rppx1_init_stats_block(rpp, stats, RPPX1_STATS_BLOCK_TYPE_WBMEAS_POST); diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c b/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c index 1dccb110d3e9..c7b24c356222 100644 --- a/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c @@ -11,10 +11,14 @@ #define EXM_START_REG 0x0004 #define EXM_CTRL_REG 0x0008 +#define EXM_CTRL_EXM_AUTOSTOP BIT(1) /* HW doc says not supported. */ #define EXM_CTRL_EXM_UPDATE_ENABLE BIT(0) #define EXM_MODE_REG 0x000c + #define EXM_CHANNEL_SEL_REG 0x0010 +#define EXM_CHANNEL_SEL_CHANNEL_SELECT_MASK GENMASK(2, 0) + #define EXM_LAST_MEAS_LINE_REG 0x0014 #define EXM_COEFF_R_REG 0x0018 #define EXM_COEFF_G_GR_REG 0x001c @@ -46,6 +50,78 @@ static int rppx1_exm_probe(struct rpp_module *mod) return 0; } +static int +rppx1_exm_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_exm_params *cfg = &block->exm; + u32 h_offs, v_offs, h_size, v_size; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + EXM_MODE_REG, 0); + return 0; + } + + switch (cfg->mode) { + case RPPX1_EXP_MEASURING_MODE_RGB: + case RPPX1_EXP_MEASURING_MODE_BAYER: + write(priv, mod->base + EXM_MODE_REG, cfg->mode); + break; + default: + write(priv, mod->base + EXM_MODE_REG, 0); + return 0; + } + + write(priv, mod->base + EXM_COEFF_R_REG, cfg->coeff_r); + write(priv, mod->base + EXM_COEFF_G_GR_REG, cfg->coeff_g_gr); + write(priv, mod->base + EXM_COEFF_GB_REG, cfg->coeff_gb); + write(priv, mod->base + EXM_COEFF_B_REG, cfg->coeff_b); + + /* Select sample point */ + write(priv, mod->base + EXM_CHANNEL_SEL_REG, + cfg->channel_sel & EXM_CHANNEL_SEL_CHANNEL_SELECT_MASK); + + /* + * Adjust and set measurement window, + * - Offsets must be even. + * - Width and height must be even and divisible in 5 windows. + */ + h_offs = cfg->wnd.h_offs & 0x1ffe; + v_offs = cfg->wnd.v_offs & 0x1ffe; + h_size = (cfg->wnd.h_size - 1) - ((cfg->wnd.h_size - 1) % 10); + v_size = (cfg->wnd.v_size - 1) - ((cfg->wnd.v_size - 1) % 10); + + write(priv, mod->base + EXM_H_OFFS_REG, h_offs); + write(priv, mod->base + EXM_V_OFFS_REG, v_offs); + write(priv, mod->base + EXM_H_SIZE_REG, h_size / 5); + write(priv, mod->base + EXM_V_SIZE_REG, v_size / 5); + + /* + * Set last measurement line for ready interrupt. Ignore the value + * from the parameters as it is only useful for fast-channel switching. + */ + write(priv, mod->base + EXM_LAST_MEAS_LINE_REG, v_offs + v_size + 1); + + write(priv, mod->base + EXM_START_REG, 1); + + return 0; +} + +static int rppx1_exm_fill_stats(struct rpp_module *mod, + union rppx1_stats_block *block) +{ + struct rppx1_exm_stats *stats = &block->exm; + + for (unsigned int i = 0; i < RPPX1_EXM_NUM_WIN; i++) + stats->exp_mean[i] = rpp_module_read(mod, EXM_MEAN_REG(i)); + + return 0; +} + const struct rpp_module_ops rppx1_exm_ops = { .probe = rppx1_exm_probe, + .fill_params = rppx1_exm_fill_params, + .fill_stats = rppx1_exm_fill_stats, }; |
