summaryrefslogtreecommitdiff
path: root/drivers/media/platform
diff options
context:
space:
mode:
authorNiklas Söderlund <niklas.soderlund+renesas@ragnatech.se>2026-07-30 19:12:33 +0200
committerSakari Ailus <sakari.ailus@linux.intel.com>2026-07-30 20:51:35 +0300
commit884d6794a816473070fa66a6b16b631861d15566 (patch)
tree08a9c2db86a4a64c8cfeab1d4191158801712a92 /drivers/media/platform
parent2151350f60d14f3e734e879cf126af32a5c48d86 (diff)
media: rppx1: wbmeas: Add support for white balance measurement
Extend the RPPX1 driver to allow setting the white balance 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/media/platform')
-rw-r--r--drivers/media/platform/dreamchip/rppx1/rpp_module.h2
-rw-r--r--drivers/media/platform/dreamchip/rppx1/rpp_params.c4
-rw-r--r--drivers/media/platform/dreamchip/rppx1/rpp_stats.c18
-rw-r--r--drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c103
4 files changed, 127 insertions, 0 deletions
diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_module.h b/drivers/media/platform/dreamchip/rppx1/rpp_module.h
index e92e77542980..64a1b848f1ea 100644
--- a/drivers/media/platform/dreamchip/rppx1/rpp_module.h
+++ b/drivers/media/platform/dreamchip/rppx1/rpp_module.h
@@ -47,10 +47,12 @@ 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_wbmeas_params wbmeas;
};
union rppx1_stats_block {
struct v4l2_isp_block_header header;
+ struct rppx1_wbmeas_stats wbmeas;
};
struct rpp_module_ops {
diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/media/platform/dreamchip/rppx1/rpp_params.c
index af45ad5750b3..7325abeba92a 100644
--- a/drivers/media/platform/dreamchip/rppx1/rpp_params.c
+++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c
@@ -17,6 +17,7 @@
static const struct v4l2_isp_params_block_type_info
rppx1_ext_params_blocks_info[] = {
+ RPPX1_PARAMS_BLOCK_INFO(WBMEAS_POST, wbmeas),
};
int rppx1_params(struct rppx1 *rpp, struct vb2_buffer *vb, size_t max_size,
@@ -50,6 +51,9 @@ int rppx1_params(struct rppx1 *rpp, struct vb2_buffer *vb, size_t max_size,
block_offset += block->header.size;
switch (block->header.type) {
+ case RPPX1_PARAMS_BLOCK_TYPE_WBMEAS_POST:
+ module = &rpp->post.wbmeas;
+ break;
default:
dev_warn(rpp->dev,
"Not handled RPPX1 block type: 0x%04x\n",
diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c b/drivers/media/platform/dreamchip/rppx1/rpp_stats.c
index f7eb60deae10..c99ea158abcf 100644
--- a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c
+++ b/drivers/media/platform/dreamchip/rppx1/rpp_stats.c
@@ -15,6 +15,11 @@
.size = sizeof(struct rppx1_ ## block ## _stats), \
}
+static const struct v4l2_isp_stats_block_type_info
+rppx1_stats_blocks_info[] = {
+ RPPX1_STATS_BLOCK_INFO(WBMEAS_POST, wbmeas),
+};
+
#define rppx1_init_stats_block(rpp, buf, type) \
((union rppx1_stats_block *) \
v4l2_isp_stats_init_block((rpp)->dev, (buf), \
@@ -24,5 +29,18 @@
void rppx1_stats_fill_isr(struct rppx1 *rpp, u32 isc, void *buf)
{
+ struct v4l2_isp_buffer *stats = buf;
+ union rppx1_stats_block *block;
+
+ v4l2_isp_stats_init_buffer(stats, V4L2_ISP_VERSION_V1);
+
+ if (isc & RPPX1_IRQ_ID_POST_AWB_MEAS) {
+ block = rppx1_init_stats_block(rpp, stats,
+ RPPX1_STATS_BLOCK_TYPE_WBMEAS_POST);
+ if (IS_ERR(block))
+ return;
+
+ rpp_module_call(&rpp->post.wbmeas, fill_stats, block);
+ }
}
EXPORT_SYMBOL_GPL(rppx1_stats_fill_isr);
diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c b/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c
index 60b9c076ec42..f0a943556238 100644
--- a/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c
+++ b/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c
@@ -57,6 +57,109 @@ static int rppx1_wbmeas_probe(struct rpp_module *mod)
return 0;
}
+static int
+rppx1_wbmeas_fill_params(struct rpp_module *mod,
+ const union rppx1_params_block *block,
+ rppx1_reg_write write, void *priv)
+{
+ const struct rppx1_wbmeas_params *cfg = &block->wbmeas;
+ u32 awb_meas_props;
+
+ /* If the modules is disabled, simply bypass it. */
+ if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) {
+ write(priv, mod->base + AWB_MEAS_PROP_REG, 0);
+ return 0;
+ }
+
+ /* Program measurement window. */
+ write(priv, mod->base + AWB_MEAS_H_OFFS_REG, cfg->wnd.h_offs);
+ write(priv, mod->base + AWB_MEAS_V_OFFS_REG, cfg->wnd.v_offs);
+ write(priv, mod->base + AWB_MEAS_H_SIZE_REG, cfg->wnd.h_size);
+ write(priv, mod->base + AWB_MEAS_V_SIZE_REG, cfg->wnd.v_size);
+
+ /* Set number of frames to sample. */
+ write(priv, mod->base + AWB_MEAS_FRAMES_REG, cfg->frames);
+
+ if (cfg->mode == RPPX1_WBMEAS_MODE_YCBCR) {
+ write(priv, mod->base + AWB_MEAS_REF_CB_MAX_B_REG,
+ cfg->ref_cb_max_b);
+ write(priv, mod->base + AWB_MEAS_REF_CR_MAX_R_REG,
+ cfg->ref_cr_max_r);
+ write(priv, mod->base + AWB_MEAS_MAX_Y_REG, cfg->max_y);
+ write(priv, mod->base + AWB_MEAS_MIN_Y_MAX_G_REG,
+ cfg->min_y_max_g);
+ write(priv, mod->base + AWB_MEAS_MAX_CSUM_REG, cfg->max_csum);
+ write(priv, mod->base + AWB_MEAS_MIN_C_REG, cfg->min_c);
+
+ /*
+ * Program the color conversion matrix coefficients and the
+ * per-color channel offsets.
+ */
+ for (unsigned int i = 0; i < 3; i++) {
+ for (unsigned int j = 0; j < 3; j++) {
+ unsigned int index = i * 3 + j;
+
+ write(priv,
+ mod->base + AWB_MEAS_CCOR_COEFF_REG(index),
+ cfg->ccor_coeff[i][j]);
+ }
+ }
+
+ write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_R_REG,
+ cfg->ccor_offs[0]);
+ write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_G_REG,
+ cfg->ccor_offs[1]);
+ write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_B_REG,
+ cfg->ccor_offs[2]);
+
+ awb_meas_props = cfg->ymax_cmp ? AWB_MEAS_PROP_YMAX : 0;
+ } else {
+ write(priv, mod->base + AWB_MEAS_REF_CB_MAX_B_REG,
+ cfg->ref_cb_max_b);
+ write(priv, mod->base + AWB_MEAS_REF_CR_MAX_R_REG,
+ cfg->ref_cr_max_r);
+ write(priv, mod->base + AWB_MEAS_MIN_Y_MAX_G_REG,
+ cfg->min_y_max_g);
+
+ /* Bypass color conversion matrix and color offsets. */
+ write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(0), 0x1000);
+ write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(1), 0x0000);
+ write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(2), 0x0000);
+ write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(3), 0x0000);
+ write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(4), 0x1000);
+ write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(5), 0x0000);
+ write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(6), 0x0000);
+ write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(7), 0x0000);
+ write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(8), 0x1000);
+ write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_R_REG, 0x00000000);
+ write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_G_REG, 0x00000000);
+ write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_B_REG, 0x00000000);
+
+ awb_meas_props = AWB_MEAS_PROP_MEAS_MODE_RGB;
+ }
+
+ write(priv, mod->base + AWB_MEAS_PROP_REG,
+ awb_meas_props | AWB_MEAS_PROP_AWB_MODE_ON);
+
+ return 0;
+}
+
+static int rppx1_wbmeas_fill_stats(struct rpp_module *mod,
+ union rppx1_stats_block *block)
+{
+ struct rppx1_wbmeas_stats *stats = &block->wbmeas;
+
+ /* Return measurements at native hardware precision. */
+ stats->cnt = rpp_module_read(mod, AWB_MEAS_WHITE_CNT_REG);
+ stats->mean_y_or_g = rpp_module_read(mod, AWB_MEAS_MEAN_Y_G_REG);
+ stats->mean_cb_or_b = rpp_module_read(mod, AWB_MEAS_MEAN_CB_B_REG);
+ stats->mean_cr_or_r = rpp_module_read(mod, AWB_MEAS_MEAN_CR_R_REG);
+
+ return 0;
+}
+
const struct rpp_module_ops rppx1_wbmeas_ops = {
.probe = rppx1_wbmeas_probe,
+ .fill_params = rppx1_wbmeas_fill_params,
+ .fill_stats = rppx1_wbmeas_fill_stats
};