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