On Thu Jul 30 19:12:37 2026 +0200, Niklas Söderlund wrote:
> Extend the RPPX1 driver to allow setting the black level measurement
> and gain configuration. 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 <[email protected]>
> Co-developed-by: Jai Luthra <[email protected]>
> Signed-off-by: Jai Luthra <[email protected]>
> Co-developed-by: Jacopo Mondi <[email protected]>
> Signed-off-by: Jacopo Mondi <[email protected]>
> Signed-off-by: Sakari Ailus <[email protected]>
Patch committed.
Thanks,
Sakari Ailus
.../media/platform/dreamchip/rppx1/rpp_module.h | 1 +
.../media/platform/dreamchip/rppx1/rpp_params.c | 5 +
drivers/media/platform/dreamchip/rppx1/rppx1_bls.c | 97 +++++++++++++++++++
include/uapi/linux/media/dreamchip/rppx1-config.h | 107 ++++++++++++++++++++-
4 files changed, 209 insertions(+), 1 deletion(-)
---
diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_module.h
b/drivers/media/platform/dreamchip/rppx1/rpp_module.h
index b134d140fe22..5e20fcdcbcc4 100644
--- a/drivers/media/platform/dreamchip/rppx1/rpp_module.h
+++ b/drivers/media/platform/dreamchip/rppx1/rpp_module.h
@@ -47,6 +47,7 @@ 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_bls_params bls;
struct rppx1_awbg_params awbg;
struct rppx1_hist_params hist;
struct rppx1_exm_params exm;
diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c
b/drivers/media/platform/dreamchip/rppx1/rpp_params.c
index 975ce3a42fb5..831cf7ca154c 100644
--- a/drivers/media/platform/dreamchip/rppx1/rpp_params.c
+++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c
@@ -17,6 +17,8 @@
static const struct v4l2_isp_params_block_type_info
rppx1_ext_params_blocks_info[] = {
+ RPPX1_PARAMS_BLOCK_INFO(BLS_PRE1, bls),
+ RPPX1_PARAMS_BLOCK_INFO(BLS_PRE2, bls),
RPPX1_PARAMS_BLOCK_INFO(AWBG_PRE1, awbg),
RPPX1_PARAMS_BLOCK_INFO(AWBG_PRE2, awbg),
RPPX1_PARAMS_BLOCK_INFO(HIST_PRE1, hist),
@@ -58,6 +60,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_BLS_PRE1:
+ module = &rpp->pre1.bls;
+ break;
case RPPX1_PARAMS_BLOCK_TYPE_AWBG_PRE1:
module = &rpp->pre1.awbg;
break;
diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c
b/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c
index 882a9a819229..01a61db279bf 100644
--- a/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c
+++ b/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c
@@ -6,6 +6,7 @@
*/
#include "rpp_module.h"
+#include "rppx1.h"
#define BLS_VERSION_REG 0x0000
@@ -32,6 +33,8 @@
#define BLS_B_MEASURED_REG 0x0040
#define BLS_C_MEASURED_REG 0x0044
#define BLS_D_MEASURED_REG 0x0048
+#define BLS_PRE1_FIXED_MASK GENMASK(24, 0)
+#define BLS_PRE2_FIXED_MASK GENMASK(12, 0)
static int rppx1_bls_probe(struct rpp_module *mod)
{
@@ -55,6 +58,100 @@ static int rppx1_bls_probe(struct rpp_module *mod)
return 0;
}
+static void
+rppx1_bls_swap_regs(struct rpp_module *mod, const u32 input[4], u32 output[4])
+{
+ static const unsigned int swap[4][4] = {
+ [RPP_RGGB] = { 0, 1, 2, 3 },
+ [RPP_GRBG] = { 1, 0, 3, 2 },
+ [RPP_GBRG] = { 2, 3, 0, 1 },
+ [RPP_BGGR] = { 3, 2, 1, 0 },
+ };
+
+ /* Swap to pattern used in our path, PRE1 or PRE2. */
+ struct rpp_module *acq = mod == &mod->rpp->pre1.bls ?
+ &mod->rpp->pre1.acq : &mod->rpp->pre2.bls;
+ enum rpp_raw_pattern pattern = acq->info.acq.raw_pattern;
+
+ for (unsigned int i = 0; i < 4; ++i)
+ output[i] = input[swap[pattern][i]];
+}
+
+static int
+rppx1_bls_fill_params(struct rpp_module *mod,
+ const union rppx1_params_block *block,
+ rppx1_reg_write write, void *priv)
+{
+ const struct rppx1_bls_params *cfg = &block->bls;
+
+ /* If the modules is disabled, simply bypass it. */
+ if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) {
+ write(priv, mod->base + BLS_CTRL_REG, 0);
+ return 0;
+ }
+
+ u32 ctrl = BLS_CTRL_BLS_EN;
+
+ if (cfg->mode == RPPX1_BLS_MODE_FIXED) {
+ static const u32 regs[] = {
+ BLS_A_FIXED_REG,
+ BLS_B_FIXED_REG,
+ BLS_C_FIXED_REG,
+ BLS_D_FIXED_REG,
+ };
+ u32 swapped[4];
+
+ rppx1_bls_swap_regs(mod, regs, swapped);
+
+ /*
+ * The PRE1 pipe fixed values are 24-bits + 1 sign bit, while
+ * the PRE2 pipe values are 12-bits + 1 sign bit.
+ */
+ u32 mask;
+
+ switch (cfg->header.type) {
+ case RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE1:
+ mask = BLS_PRE1_FIXED_MASK;
+ break;
+ case RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE2:
+ mask = BLS_PRE2_FIXED_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ write(priv, mod->base + swapped[0], cfg->fixed.a & mask);
+ write(priv, mod->base + swapped[1], cfg->fixed.b & mask);
+ write(priv, mod->base + swapped[2], cfg->fixed.c & mask);
+ write(priv, mod->base + swapped[3], cfg->fixed.d & mask);
+ } else {
+ write(priv, mod->base + BLS_SAMPLES_REG, cfg->samples);
+
+ if (cfg->en_windows & RPPX1_BLS_WIN_EN_WIN1) {
+ write(priv, mod->base + BLS_H1_START_REG,
cfg->window1.h_offs);
+ write(priv, mod->base + BLS_H1_STOP_REG,
cfg->window1.h_size);
+ write(priv, mod->base + BLS_V1_START_REG,
cfg->window1.v_offs);
+ write(priv, mod->base + BLS_V1_STOP_REG,
cfg->window1.v_size);
+ ctrl |= BLS_CTRL_BLS_WIN1;
+ }
+
+ if (cfg->en_windows & RPPX1_BLS_WIN_EN_WIN2) {
+ write(priv, mod->base + BLS_H2_START_REG,
cfg->window2.h_offs);
+ write(priv, mod->base + BLS_H2_STOP_REG,
cfg->window2.h_size);
+ write(priv, mod->base + BLS_V2_START_REG,
cfg->window2.v_offs);
+ write(priv, mod->base + BLS_V2_STOP_REG,
cfg->window2.v_size);
+ ctrl |= BLS_CTRL_BLS_WIN2;
+ }
+
+ ctrl |= BLS_CTRL_BLS_MODE_MEASURED;
+ }
+
+ write(priv, mod->base + BLS_CTRL_REG, ctrl);
+
+ return 0;
+}
+
const struct rpp_module_ops rppx1_bls_ops = {
.probe = rppx1_bls_probe,
+ .fill_params = rppx1_bls_fill_params,
};
diff --git a/include/uapi/linux/media/dreamchip/rppx1-config.h
b/include/uapi/linux/media/dreamchip/rppx1-config.h
index 934e18731b08..0049977870ad 100644
--- a/include/uapi/linux/media/dreamchip/rppx1-config.h
+++ b/include/uapi/linux/media/dreamchip/rppx1-config.h
@@ -85,6 +85,8 @@ enum rppx1_meas_chan {
* @RPPX1_PARAMS_BLOCK_TYPE_HIST_PRE1: PRE1 pipe Histogram Measurement
* @RPPX1_PARAMS_BLOCK_TYPE_HIST_PRE2: PRE2 pipe Histogram Measurement
* @RPPX1_PARAMS_BLOCK_TYPE_HIST_POST: POST pipe Histogram Measurement
+ * @RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE1: PRE1 pipe Black Level Subtraction
+ * @RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE2: PRE2 pipe Black Level Subtraction
*/
enum rppx1_params_block_type {
RPPX1_PARAMS_BLOCK_TYPE_WBMEAS_POST,
@@ -96,6 +98,8 @@ enum rppx1_params_block_type {
RPPX1_PARAMS_BLOCK_TYPE_HIST_PRE1,
RPPX1_PARAMS_BLOCK_TYPE_HIST_PRE2,
RPPX1_PARAMS_BLOCK_TYPE_HIST_POST,
+ RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE1,
+ RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE2,
};
/**
@@ -330,6 +334,105 @@ struct rppx1_hist_params {
__u8 reserved;
};
+/**
+ * struct rppx1_bls_fixed - BLS fixed subtraction values
+ *
+ * Fixed black level values subtracted from sensor data per Bayer channel.
+ * Negative values result in addition.
+ *
+ * The PRE1 pipe BLS module operates on a 24-bits input data and fixed black
+ * levels are stored as a signed 2's complement representation ranging from
+ * -2^24 to 2^24-1.
+ *
+ * The PRE2 pipe BLS module operates on a 12-bits input data and fixed black
+ * levels are stored as a signed 2's complement representation ranging from
+ * -2^12 to 2^12-1.
+ *
+ * Userspace is expected to provide fixed black level values with a bit-depth
+ * matching the one of pipe in use.
+ *
+ * These subtraction values are matched with the sensor native Bayer components
+ * ordering according to the cropping configuration on the input port.
+ *
+ * @a: subtraction value for channel A
+ * @b: subtraction value for channel B
+ * @c: subtraction value for channel C
+ * @d: subtraction value for channel D
+ */
+struct rppx1_bls_fixed {
+ __u32 a;
+ __u32 b;
+ __u32 c;
+ __u32 d;
+};
+
+/**
+ * enum rppx1_bls_mode - BLS subtraction mode
+ *
+ * Select if subtracted black level come from fixed or measured values.
+ *
+ * @RPPX1_BLS_MODE_FIXED: subtract fixed values
+ * @RPPX1_BLS_MODE_MEAS: subtract measured values
+ */
+enum rppx1_bls_mode {
+ RPPX1_BLS_MODE_FIXED,
+ RPPX1_BLS_MODE_MEAS,
+};
+
+/**
+ * enum rppx1_bls_win_en: BLS measurement configuration
+ *
+ * Select the measurement window to use for measured black level values.
+ *
+ * @RPPX1_BLS_WIN_EN_OFF: disable measurement
+ * @RPPX1_BLS_WIN_EN_WIN1: Enable measurement from window 1
+ * @RPPX1_BLS_WIN_EN_WIN2: enable measurement from window 2
+ * @RPPX1_BLS_WIN_EN_WIN12: enable measurement from window 1 and window 2
+ */
+enum rppx1_bls_win_en {
+ RPPX1_BLS_WIN_EN_OFF,
+ RPPX1_BLS_WIN_EN_WIN1,
+ RPPX1_BLS_WIN_EN_WIN2,
+ RPPX1_BLS_WIN_EN_WIN12,
+};
+
+/**
+ * struct rppx1_bls_params - RPP-X1 Black Level Subtraction Module
+ *
+ * The RPP-X1 Black Level Subtraction module is available on the PRE1 and PRE2
+ * pre-fusion pipes. Userspace selects which pipe to operate by setting the
+ * @header.type field to RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE1 or
+ * RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE2.
+ *
+ * The BLS module operates on fixed or measured data according to the setting
of
+ * the @mode field. When RPPX1_BLS_MODE_FIXED is used userspace shall provide
+ * the per-channel black levels in @fixed. When RPPX1_BLS_MODE_MEAS is used
+ * userspace shall configure the measurement windows @window1 and optionally
+ * @window2 to select the optically black pixels region in the input frame. The
+ * @samples fields controls how many measure samples are used for averaging the
+ * measured black levels.
+ *
+ * @header: block header (type = RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE1 or
+ * type == RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE2)
+ * @window1: BLS measurement window 1 (14 bits)
+ * @window2: BLS measurement window 2 (14 bits)
+ * @fixed: fixed subtraction values (see enum rppx1_bls_fixed)
+ * @mode: BLS subtraction mode (see enum rppx1_bls_mode)
+ * @en_windows: BLS measurement mode (see rppx1_bls_win_en)
+ * @samples: log2 of the number of measured pixels per Bayer position
+ * @reserved: padding
+ */
+struct rppx1_bls_params {
+ struct v4l2_isp_params_block_header header;
+ struct rppx1_window window1;
+ struct rppx1_window window2;
+ struct rppx1_bls_fixed fixed;
+ __u8 mode;
+ __u8 en_windows;
+ __u8 samples;
+ __u8 reserved[5];
+};
+
/**
* RPPX1_PARAMS_MAX_SIZE - Maximum size of all RPP-X1 parameter blocks
*
@@ -345,7 +448,9 @@ struct rppx1_hist_params {
sizeof(struct rppx1_exm_params) + \
sizeof(struct rppx1_hist_params) + \
sizeof(struct rppx1_hist_params) + \
- sizeof(struct rppx1_hist_params))
+ sizeof(struct rppx1_hist_params) + \
+ sizeof(struct rppx1_bls_params) + \
+ sizeof(struct rppx1_bls_params))
/* ---------------------------------------------------------------------------
* Statistics Structures
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]