[v7,5/5] ipa: mali-c55: Introduce MaliC55Params
diff mbox series

Message ID 20251215-v4l2-params-v7-5-be2b8c75ad09@ideasonboard.com
State New
Headers show
Series
  • ipa: libipa: Introduce V4L2Params
Related show

Commit Message

Jacopo Mondi Dec. 15, 2025, 3:11 p.m. UTC
Implement MaliC55Params to derive from V4L2Params and use the new
helpers in the Mali C55 IPA algorithms implementation.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Tested-by: Antoine Bouyer <antoine.bouyer@nxp.com>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
---
 src/ipa/mali-c55/algorithms/agc.cpp | 87 +++++++++++++++----------------------
 src/ipa/mali-c55/algorithms/agc.h   | 14 +++---
 src/ipa/mali-c55/algorithms/awb.cpp | 64 +++++++++++----------------
 src/ipa/mali-c55/algorithms/awb.h   | 10 ++---
 src/ipa/mali-c55/algorithms/blc.cpp | 20 +++------
 src/ipa/mali-c55/algorithms/blc.h   |  3 +-
 src/ipa/mali-c55/algorithms/lsc.cpp | 58 ++++++++++---------------
 src/ipa/mali-c55/algorithms/lsc.h   |  8 ++--
 src/ipa/mali-c55/mali-c55.cpp       | 20 +++------
 src/ipa/mali-c55/module.h           |  3 +-
 src/ipa/mali-c55/params.h           | 77 ++++++++++++++++++++++++++++++++
 11 files changed, 191 insertions(+), 173 deletions(-)

Comments

Kieran Bingham Dec. 15, 2025, 5:14 p.m. UTC | #1
Quoting Jacopo Mondi (2025-12-15 15:11:25)
> Implement MaliC55Params to derive from V4L2Params and use the new
> helpers in the Mali C55 IPA algorithms implementation.
> 
> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> Tested-by: Antoine Bouyer <antoine.bouyer@nxp.com>
> Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>

Well I got all the way to the bottom. It's terse, but there's nothing
that jumped out to me as incorrect - and it's all about converting to
the new types so:


Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> ---
>  src/ipa/mali-c55/algorithms/agc.cpp | 87 +++++++++++++++----------------------
>  src/ipa/mali-c55/algorithms/agc.h   | 14 +++---
>  src/ipa/mali-c55/algorithms/awb.cpp | 64 +++++++++++----------------
>  src/ipa/mali-c55/algorithms/awb.h   | 10 ++---
>  src/ipa/mali-c55/algorithms/blc.cpp | 20 +++------
>  src/ipa/mali-c55/algorithms/blc.h   |  3 +-
>  src/ipa/mali-c55/algorithms/lsc.cpp | 58 ++++++++++---------------
>  src/ipa/mali-c55/algorithms/lsc.h   |  8 ++--
>  src/ipa/mali-c55/mali-c55.cpp       | 20 +++------
>  src/ipa/mali-c55/module.h           |  3 +-
>  src/ipa/mali-c55/params.h           | 77 ++++++++++++++++++++++++++++++++
>  11 files changed, 191 insertions(+), 173 deletions(-)
> 
> diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp
> index 78e7e07b2348a711e6261bac45e006f49a59513a..5d60cd8c9ff8a90e2e48e5d6939b538135b7ec3d 100644
> --- a/src/ipa/mali-c55/algorithms/agc.cpp
> +++ b/src/ipa/mali-c55/algorithms/agc.cpp
> @@ -241,8 +241,8 @@ void Agc::queueRequest(IPAContext &context, const uint32_t frame,
>         }
>  }
>  
> -size_t Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContext,
> -                              mali_c55_params_block block)
> +void Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContext,
> +                            MaliC55Params *params)
>  {
>         IPAActiveState &activeState = context.activeState;
>         double gain;
> @@ -252,52 +252,50 @@ size_t Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContex
>         else
>                 gain = activeState.agc.manual.ispGain;
>  
> -       block.header->type = MALI_C55_PARAM_BLOCK_DIGITAL_GAIN;
> -       block.header->flags = 0;
> -       block.header->size = sizeof(struct mali_c55_params_digital_gain);
> +       auto block = params->block<MaliC55Blocks::Dgain>();
> +       block->gain = floatingToFixedPoint<5, 8, uint16_t, double>(gain);
>  
> -       block.digital_gain->gain = floatingToFixedPoint<5, 8, uint16_t, double>(gain);
>         frameContext.agc.ispGain = gain;
> -
> -       return block.header->size;
>  }
>  
> -size_t Agc::fillParamsBuffer(mali_c55_params_block block,
> -                            enum mali_c55_param_block_type type)
> +void Agc::fillParamsBuffer(MaliC55Params *params, enum MaliC55Blocks type)
>  {
> -       block.header->type = type;
> -       block.header->flags = 0;
> -       block.header->size = sizeof(struct mali_c55_params_aexp_hist);
> +
> +       assert(type == MaliC55Blocks::AexpHist || type == MaliC55Blocks::AexpIhist);
> +
> +       auto block = type == MaliC55Blocks::AexpHist ?
> +                       params->block<MaliC55Blocks::AexpHist>() :
> +                       params->block<MaliC55Blocks::AexpIhist>();
>  
>         /* Collect every 3rd pixel horizontally */
> -       block.aexp_hist->skip_x = 1;
> +       block->skip_x = 1;
>         /* Start from first column */
> -       block.aexp_hist->offset_x = 0;
> +       block->offset_x = 0;
>         /* Collect every pixel vertically */
> -       block.aexp_hist->skip_y = 0;
> +       block->skip_y = 0;
>         /* Start from the first row */
> -       block.aexp_hist->offset_y = 0;
> +       block->offset_y = 0;
>         /* 1x scaling (i.e. none) */
> -       block.aexp_hist->scale_bottom = 0;
> -       block.aexp_hist->scale_top = 0;
> +       block->scale_bottom = 0;
> +       block->scale_top = 0;
>         /* Collect all Bayer planes into 4 separate histograms */
> -       block.aexp_hist->plane_mode = 1;
> +       block->plane_mode = 1;
>         /* Tap the data immediately after the digital gain block */
> -       block.aexp_hist->tap_point = MALI_C55_AEXP_HIST_TAP_FS;
> -
> -       return block.header->size;
> +       block->tap_point = MALI_C55_AEXP_HIST_TAP_FS;
>  }
>  
> -size_t Agc::fillWeightsArrayBuffer(mali_c55_params_block block,
> -                                  enum mali_c55_param_block_type type)
> +void Agc::fillWeightsArrayBuffer(MaliC55Params *params, const enum MaliC55Blocks type)
>  {
> -       block.header->type = type;
> -       block.header->flags = 0;
> -       block.header->size = sizeof(struct mali_c55_params_aexp_weights);
> +       assert(type == MaliC55Blocks::AexpHistWeights ||
> +              type == MaliC55Blocks::AexpIhistWeights);
> +
> +       auto block = type == MaliC55Blocks::AexpHistWeights ?
> +                       params->block<MaliC55Blocks::AexpHistWeights>() :
> +                       params->block<MaliC55Blocks::AexpIhistWeights>();
>  
>         /* We use every zone - a 15x15 grid */
> -       block.aexp_weights->nodes_used_horiz = 15;
> -       block.aexp_weights->nodes_used_vert = 15;
> +       block->nodes_used_horiz = 15;
> +       block->nodes_used_vert = 15;
>  
>         /*
>          * We uniformly weight the zones to 1 - this results in the collected
> @@ -305,40 +303,25 @@ size_t Agc::fillWeightsArrayBuffer(mali_c55_params_block block,
>          * approximate colour channel averages for the image.
>          */
>         Span<uint8_t> weights{
> -               block.aexp_weights->zone_weights,
> +               block->zone_weights,
>                 MALI_C55_MAX_ZONES
>         };
>         std::fill(weights.begin(), weights.end(), 1);
> -
> -       return block.header->size;
>  }
>  
>  void Agc::prepare(IPAContext &context, const uint32_t frame,
> -                 IPAFrameContext &frameContext, v4l2_isp_params_buffer *params)
> +                 IPAFrameContext &frameContext, MaliC55Params *params)
>  {
> -       mali_c55_params_block block;
> -
> -       block.data = &params->data[params->data_size];
> -       params->data_size += fillGainParamBlock(context, frameContext, block);
> +       fillGainParamBlock(context, frameContext, params);
>  
>         if (frame > 0)
>                 return;
>  
> -       block.data = &params->data[params->data_size];
> -       params->data_size += fillParamsBuffer(block,
> -                                              MALI_C55_PARAM_BLOCK_AEXP_HIST);
> -
> -       block.data = &params->data[params->data_size];
> -       params->data_size += fillWeightsArrayBuffer(block,
> -                                                    MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS);
> -
> -       block.data = &params->data[params->data_size];
> -       params->data_size += fillParamsBuffer(block,
> -                                              MALI_C55_PARAM_BLOCK_AEXP_IHIST);
> +       fillParamsBuffer(params, MaliC55Blocks::AexpHist);
> +       fillWeightsArrayBuffer(params, MaliC55Blocks::AexpHistWeights);
>  
> -       block.data = &params->data[params->data_size];
> -       params->data_size += fillWeightsArrayBuffer(block,
> -                                                    MALI_C55_PARAM_BLOCK_AEXP_IHIST_WEIGHTS);
> +       fillParamsBuffer(params, MaliC55Blocks::AexpIhist);
> +       fillWeightsArrayBuffer(params, MaliC55Blocks::AexpIhistWeights);
>  }
>  
>  double Agc::estimateLuminance(const double gain) const
> diff --git a/src/ipa/mali-c55/algorithms/agc.h b/src/ipa/mali-c55/algorithms/agc.h
> index 4325ef5a9b7dcef36107b64a65db993f194d4167..9684fff664bc67d287bb00f8dc88e238d8dd0cea 100644
> --- a/src/ipa/mali-c55/algorithms/agc.h
> +++ b/src/ipa/mali-c55/algorithms/agc.h
> @@ -57,7 +57,7 @@ public:
>                           const ControlList &controls) override;
>         void prepare(IPAContext &context, const uint32_t frame,
>                      IPAFrameContext &frameContext,
> -                    v4l2_isp_params_buffer *params) override;
> +                    MaliC55Params *params) override;
>         void process(IPAContext &context, const uint32_t frame,
>                      IPAFrameContext &frameContext,
>                      const mali_c55_stats_buffer *stats,
> @@ -65,13 +65,11 @@ public:
>  
>  private:
>         double estimateLuminance(const double gain) const override;
> -       size_t fillGainParamBlock(IPAContext &context,
> -                                 IPAFrameContext &frameContext,
> -                                 mali_c55_params_block block);
> -       size_t fillParamsBuffer(mali_c55_params_block block,
> -                               enum mali_c55_param_block_type type);
> -       size_t fillWeightsArrayBuffer(mali_c55_params_block block,
> -                                     enum mali_c55_param_block_type type);
> +       void fillGainParamBlock(IPAContext &context,
> +                               IPAFrameContext &frameContext,
> +                               MaliC55Params *params);
> +       void fillParamsBuffer(MaliC55Params *params, enum MaliC55Blocks type);
> +       void fillWeightsArrayBuffer(MaliC55Params *params, enum MaliC55Blocks type);
>  
>         AgcStatistics statistics_;
>  };
> diff --git a/src/ipa/mali-c55/algorithms/awb.cpp b/src/ipa/mali-c55/algorithms/awb.cpp
> index 694c0aaa9c6804bb58e380ba9c744f11c39224fe..964e810882a93cce02f991675d74bbf163d51e7c 100644
> --- a/src/ipa/mali-c55/algorithms/awb.cpp
> +++ b/src/ipa/mali-c55/algorithms/awb.cpp
> @@ -43,13 +43,9 @@ int Awb::configure([[maybe_unused]] IPAContext &context,
>         return 0;
>  }
>  
> -size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context,
> +void Awb::fillGainsParamBlock(MaliC55Params *params, IPAContext &context,
>                                 IPAFrameContext &frameContext)
>  {
> -       block.header->type = MALI_C55_PARAM_BLOCK_AWB_GAINS;
> -       block.header->flags = 0;
> -       block.header->size = sizeof(struct mali_c55_params_awb_gains);
> -
>         double rGain = context.activeState.awb.rGain;
>         double bGain = context.activeState.awb.bGain;
>  
> @@ -63,34 +59,32 @@ size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context
>          * This holds true regardless of the bayer order of the input data, as
>          * the mapping is done internally in the ISP.
>          */
> -       block.awb_gains->gain00 = floatingToFixedPoint<4, 8, uint16_t, double>(rGain);
> -       block.awb_gains->gain01 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);
> -       block.awb_gains->gain10 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);
> -       block.awb_gains->gain11 = floatingToFixedPoint<4, 8, uint16_t, double>(bGain);
> +       auto block = params->block<MaliC55Blocks::AwbGains>();
> +
> +       block->gain00 = floatingToFixedPoint<4, 8, uint16_t, double>(rGain);
> +       block->gain01 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);
> +       block->gain10 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);
> +       block->gain11 = floatingToFixedPoint<4, 8, uint16_t, double>(bGain);
>  
>         frameContext.awb.rGain = rGain;
>         frameContext.awb.bGain = bGain;
> -
> -       return sizeof(struct mali_c55_params_awb_gains);
>  }
>  
> -size_t Awb::fillConfigParamBlock(mali_c55_params_block block)
> +void Awb::fillConfigParamBlock(MaliC55Params *params)
>  {
> -       block.header->type = MALI_C55_PARAM_BLOCK_AWB_CONFIG;
> -       block.header->flags = 0;
> -       block.header->size = sizeof(struct mali_c55_params_awb_config);
> +       auto block = params->block<MaliC55Blocks::AwbConfig>();
>  
>         /* Tap the stats after the purple fringe block */
> -       block.awb_config->tap_point = MALI_C55_AWB_STATS_TAP_PF;
> +       block->tap_point = MALI_C55_AWB_STATS_TAP_PF;
>  
>         /* Get R/G and B/G ratios as statistics */
> -       block.awb_config->stats_mode = MALI_C55_AWB_MODE_RGBG;
> +       block->stats_mode = MALI_C55_AWB_MODE_RGBG;
>  
>         /* Default white level */
> -       block.awb_config->white_level = 1023;
> +       block->white_level = 1023;
>  
>         /* Default black level */
> -       block.awb_config->black_level = 0;
> +       block->black_level = 0;
>  
>         /*
>          * By default pixels are included who's colour ratios are bounded in a
> @@ -104,40 +98,34 @@ size_t Awb::fillConfigParamBlock(mali_c55_params_block block)
>          *
>          * \todo should these perhaps be tunable?
>          */
> -       block.awb_config->cr_max = 511;
> -       block.awb_config->cr_min = 64;
> -       block.awb_config->cb_max = 511;
> -       block.awb_config->cb_min = 64;
> +       block->cr_max = 511;
> +       block->cr_min = 64;
> +       block->cb_max = 511;
> +       block->cb_min = 64;
>  
>         /* We use the full 15x15 zoning scheme */
> -       block.awb_config->nodes_used_horiz = 15;
> -       block.awb_config->nodes_used_vert = 15;
> +       block->nodes_used_horiz = 15;
> +       block->nodes_used_vert = 15;
>  
>         /*
>          * We set the trimming boundaries equivalent to the main boundaries. In
>          * other words; no trimming.
>          */
> -       block.awb_config->cr_high = 511;
> -       block.awb_config->cr_low = 64;
> -       block.awb_config->cb_high = 511;
> -       block.awb_config->cb_low = 64;
> -
> -       return sizeof(struct mali_c55_params_awb_config);
> +       block->cr_high = 511;
> +       block->cr_low = 64;
> +       block->cb_high = 511;
> +       block->cb_low = 64;
>  }
>  
>  void Awb::prepare(IPAContext &context, const uint32_t frame,
> -                 IPAFrameContext &frameContext, v4l2_isp_params_buffer *params)
> +                 IPAFrameContext &frameContext, MaliC55Params *params)
>  {
> -       mali_c55_params_block block;
> -       block.data = &params->data[params->data_size];
> -
> -       params->data_size += fillGainsParamBlock(block, context, frameContext);
> +       fillGainsParamBlock(params, context, frameContext);
>  
>         if (frame > 0)
>                 return;
>  
> -       block.data = &params->data[params->data_size];
> -       params->data_size += fillConfigParamBlock(block);
> +       fillConfigParamBlock(params);
>  }
>  
>  void Awb::process(IPAContext &context, const uint32_t frame,
> diff --git a/src/ipa/mali-c55/algorithms/awb.h b/src/ipa/mali-c55/algorithms/awb.h
> index 647525ff700e8281e3cce63e64ba56a91294bcc2..683a62af263a14d2f5d5b261448953ada6669b2f 100644
> --- a/src/ipa/mali-c55/algorithms/awb.h
> +++ b/src/ipa/mali-c55/algorithms/awb.h
> @@ -22,17 +22,17 @@ public:
>                       const IPACameraSensorInfo &configInfo) override;
>         void prepare(IPAContext &context, const uint32_t frame,
>                      IPAFrameContext &frameContext,
> -                    v4l2_isp_params_buffer *params) override;
> +                    MaliC55Params *params) override;
>         void process(IPAContext &context, const uint32_t frame,
>                      IPAFrameContext &frameContext,
>                      const mali_c55_stats_buffer *stats,
>                      ControlList &metadata) override;
>  
>  private:
> -       size_t fillGainsParamBlock(mali_c55_params_block block,
> -                                  IPAContext &context,
> -                                  IPAFrameContext &frameContext);
> -       size_t fillConfigParamBlock(mali_c55_params_block block);
> +       void fillGainsParamBlock(MaliC55Params *params,
> +                                IPAContext &context,
> +                                IPAFrameContext &frameContext);
> +       void fillConfigParamBlock(MaliC55Params *params);
>  };
>  
>  } /* namespace ipa::mali_c55::algorithms */
> diff --git a/src/ipa/mali-c55/algorithms/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp
> index 543ba96cb57ac0cca2b8f822180d8d8b42f21fc7..d099219c3e43ec96fa452ed13fa46ada2025edc9 100644
> --- a/src/ipa/mali-c55/algorithms/blc.cpp
> +++ b/src/ipa/mali-c55/algorithms/blc.cpp
> @@ -85,27 +85,19 @@ int BlackLevelCorrection::configure(IPAContext &context,
>  void BlackLevelCorrection::prepare([[maybe_unused]] IPAContext &context,
>                                    const uint32_t frame,
>                                    [[maybe_unused]] IPAFrameContext &frameContext,
> -                                  v4l2_isp_params_buffer *params)
> +                                  MaliC55Params *params)
>  {
> -       mali_c55_params_block block;
> -       block.data = &params->data[params->data_size];
> -
>         if (frame > 0)
>                 return;
>  
>         if (!tuningParameters_)
>                 return;
>  
> -       block.header->type = MALI_C55_PARAM_BLOCK_SENSOR_OFFS;
> -       block.header->flags = 0;
> -       block.header->size = sizeof(mali_c55_params_sensor_off_preshading);
> -
> -       block.sensor_offs->chan00 = offset00;
> -       block.sensor_offs->chan01 = offset01;
> -       block.sensor_offs->chan10 = offset10;
> -       block.sensor_offs->chan11 = offset11;
> -
> -       params->data_size += block.header->size;
> +       auto block = params->block<MaliC55Blocks::Bls>();
> +       block->chan00 = offset00;
> +       block->chan01 = offset01;
> +       block->chan10 = offset10;
> +       block->chan11 = offset11;
>  }
>  
>  void BlackLevelCorrection::process([[maybe_unused]] IPAContext &context,
> diff --git a/src/ipa/mali-c55/algorithms/blc.h b/src/ipa/mali-c55/algorithms/blc.h
> index ee6c889ed89ac2230b231cb58a9fe4412c0ce164..fc5a7ea310cbdbcf271eb26c73b17243aea744cd 100644
> --- a/src/ipa/mali-c55/algorithms/blc.h
> +++ b/src/ipa/mali-c55/algorithms/blc.h
> @@ -6,6 +6,7 @@
>   */
>  
>  #include "algorithm.h"
> +#include "params.h"
>  
>  namespace libcamera {
>  
> @@ -22,7 +23,7 @@ public:
>                       const IPACameraSensorInfo &configInfo) override;
>         void prepare(IPAContext &context, const uint32_t frame,
>                      IPAFrameContext &frameContext,
> -                    v4l2_isp_params_buffer *params) override;
> +                    MaliC55Params *params) override;
>         void process(IPAContext &context, const uint32_t frame,
>                      IPAFrameContext &frameContext,
>                      const mali_c55_stats_buffer *stats,
> diff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp
> index cb915c5efd3c22952035f2b03ee659f293942ec9..5b042c757bc70fe4eb4a5aaa848266b3afce9100 100644
> --- a/src/ipa/mali-c55/algorithms/lsc.cpp
> +++ b/src/ipa/mali-c55/algorithms/lsc.cpp
> @@ -108,41 +108,33 @@ int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData
>         return 0;
>  }
>  
> -size_t Lsc::fillConfigParamsBlock(mali_c55_params_block block) const
> +void Lsc::fillConfigParamsBlock(MaliC55Params *params) const
>  {
> -       block.header->type = MALI_C55_PARAM_MESH_SHADING_CONFIG;
> -       block.header->flags = 0;
> -       block.header->size = sizeof(struct mali_c55_params_mesh_shading_config);
> +       auto block = params->block<MaliC55Blocks::MeshShadingConfig>();
>  
> -       block.shading_config->mesh_show = false;
> -       block.shading_config->mesh_scale = meshScale_;
> -       block.shading_config->mesh_page_r = 0;
> -       block.shading_config->mesh_page_g = 1;
> -       block.shading_config->mesh_page_b = 2;
> -       block.shading_config->mesh_width = meshSize_;
> -       block.shading_config->mesh_height = meshSize_;
> +       block->mesh_show = false;
> +       block->mesh_scale = meshScale_;
> +       block->mesh_page_r = 0;
> +       block->mesh_page_g = 1;
> +       block->mesh_page_b = 2;
> +       block->mesh_width = meshSize_;
> +       block->mesh_height = meshSize_;
>  
> -       std::copy(mesh_.begin(), mesh_.end(), block.shading_config->mesh);
> -
> -       return block.header->size;
> +       std::copy(mesh_.begin(), mesh_.end(), block->mesh);
>  }
>  
> -size_t Lsc::fillSelectionParamsBlock(mali_c55_params_block block, uint8_t bank,
> +void Lsc::fillSelectionParamsBlock(MaliC55Params *params, uint8_t bank,
>                                      uint8_t alpha) const
>  {
> -       block.header->type = MALI_C55_PARAM_MESH_SHADING_SELECTION;
> -       block.header->flags = 0;
> -       block.header->size = sizeof(struct mali_c55_params_mesh_shading_selection);
> -
> -       block.shading_selection->mesh_alpha_bank_r = bank;
> -       block.shading_selection->mesh_alpha_bank_g = bank;
> -       block.shading_selection->mesh_alpha_bank_b = bank;
> -       block.shading_selection->mesh_alpha_r = alpha;
> -       block.shading_selection->mesh_alpha_g = alpha;
> -       block.shading_selection->mesh_alpha_b = alpha;
> -       block.shading_selection->mesh_strength = 0x1000; /* Otherwise known as 1.0 */
> -
> -       return block.header->size;
> +       auto block = params->block<MaliC55Blocks::MeshShadingSel>();
> +
> +       block->mesh_alpha_bank_r = bank;
> +       block->mesh_alpha_bank_g = bank;
> +       block->mesh_alpha_bank_b = bank;
> +       block->mesh_alpha_r = alpha;
> +       block->mesh_alpha_g = alpha;
> +       block->mesh_alpha_b = alpha;
> +       block->mesh_strength = 0x1000; /* Otherwise known as 1.0 */
>  }
>  
>  std::tuple<uint8_t, uint8_t> Lsc::findBankAndAlpha(uint32_t ct) const
> @@ -170,7 +162,7 @@ std::tuple<uint8_t, uint8_t> Lsc::findBankAndAlpha(uint32_t ct) const
>  
>  void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
>                   [[maybe_unused]] IPAFrameContext &frameContext,
> -                 v4l2_isp_params_buffer *params)
> +                 MaliC55Params *params)
>  {
>         /*
>          * For each frame we assess the colour temperature of the **last** frame
> @@ -193,10 +185,7 @@ void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
>                 std::tie(bank, alpha) = findBankAndAlpha(temperatureK);
>         }
>  
> -       mali_c55_params_block block;
> -       block.data = &params->data[params->data_size];
> -
> -       params->data_size += fillSelectionParamsBlock(block, bank, alpha);
> +       fillSelectionParamsBlock(params, bank, alpha);
>  
>         if (frame > 0)
>                 return;
> @@ -205,8 +194,7 @@ void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
>          * If this is the first frame, we need to load the parsed coefficient
>          * tables from tuning data to the ISP.
>          */
> -       block.data = &params->data[params->data_size];
> -       params->data_size += fillConfigParamsBlock(block);
> +       fillConfigParamsBlock(params);
>  }
>  
>  REGISTER_IPA_ALGORITHM(Lsc, "Lsc")
> diff --git a/src/ipa/mali-c55/algorithms/lsc.h b/src/ipa/mali-c55/algorithms/lsc.h
> index c287900502528ca82ab6c62d732b6ffc28ad8df6..e7092bc74a0b0301463167d16e1e888696547d10 100644
> --- a/src/ipa/mali-c55/algorithms/lsc.h
> +++ b/src/ipa/mali-c55/algorithms/lsc.h
> @@ -23,15 +23,15 @@ public:
>         int init(IPAContext &context, const YamlObject &tuningData) override;
>         void prepare(IPAContext &context, const uint32_t frame,
>                      IPAFrameContext &frameContext,
> -                    v4l2_isp_params_buffer *params) override;
> +                    MaliC55Params *params) override;
>  private:
>         static constexpr unsigned int kRedOffset = 0;
>         static constexpr unsigned int kGreenOffset = 1024;
>         static constexpr unsigned int kBlueOffset = 2048;
>  
> -       size_t fillConfigParamsBlock(mali_c55_params_block block) const;
> -       size_t fillSelectionParamsBlock(mali_c55_params_block block,
> -                                       uint8_t bank, uint8_t alpha) const;
> +       void fillConfigParamsBlock(MaliC55Params *params) const;
> +       void fillSelectionParamsBlock(MaliC55Params *params,
> +                                     uint8_t bank, uint8_t alpha) const;
>         std::tuple<uint8_t, uint8_t> findBankAndAlpha(uint32_t ct) const;
>  
>         std::vector<uint32_t> mesh_ = std::vector<uint32_t>(3072);
> diff --git a/src/ipa/mali-c55/mali-c55.cpp b/src/ipa/mali-c55/mali-c55.cpp
> index 3f56604a0488dc853800ad54a54378166d7a112b..1d2a4f75cf8c7908ecebd02e71028d9f84ab1f94 100644
> --- a/src/ipa/mali-c55/mali-c55.cpp
> +++ b/src/ipa/mali-c55/mali-c55.cpp
> @@ -30,6 +30,7 @@
>  #include "libipa/camera_sensor_helper.h"
>  
>  #include "ipa_context.h"
> +#include "params.h"
>  
>  namespace libcamera {
>  
> @@ -333,24 +334,13 @@ void IPAMaliC55::queueRequest(const uint32_t request, const ControlList &control
>  void IPAMaliC55::fillParams(unsigned int request,
>                             [[maybe_unused]] uint32_t bufferId)
>  {
> -       struct v4l2_isp_params_buffer *params;
>         IPAFrameContext &frameContext = context_.frameContexts.get(request);
> +       MaliC55Params params(buffers_.at(bufferId).planes()[0]);
>  
> -       params = reinterpret_cast<v4l2_isp_params_buffer *>(
> -               buffers_.at(bufferId).planes()[0].data());
> -       memset(params, 0,
> -              buffers_.at(bufferId).planes()[0].size());
> -
> -       params->version = V4L2_ISP_PARAMS_VERSION_V1;
> -
> -       for (auto const &algo : algorithms()) {
> -               algo->prepare(context_, request, frameContext, params);
> -
> -               ASSERT(params->data_size <= MALI_C55_PARAMS_MAX_SIZE);
> -       }
> +       for (auto const &algo : algorithms())
> +               algo->prepare(context_, request, frameContext, &params);
>  
> -       size_t bytesused = offsetof(struct v4l2_isp_params_buffer, data) + params->data_size;
> -       paramsComputed.emit(request, bytesused);
> +       paramsComputed.emit(request, params.bytesused());
>  }
>  
>  void IPAMaliC55::processStats(unsigned int request, unsigned int bufferId,
> diff --git a/src/ipa/mali-c55/module.h b/src/ipa/mali-c55/module.h
> index a8dcb20841a4ebd7bde22cae4ff1f8eef530d8bb..13b34eb2839530a3518340165e6ca895d0f6bcaf 100644
> --- a/src/ipa/mali-c55/module.h
> +++ b/src/ipa/mali-c55/module.h
> @@ -14,13 +14,14 @@
>  #include <libipa/module.h>
>  
>  #include "ipa_context.h"
> +#include "params.h"
>  
>  namespace libcamera {
>  
>  namespace ipa::mali_c55 {
>  
>  using Module = ipa::Module<IPAContext, IPAFrameContext, IPACameraSensorInfo,
> -                          v4l2_isp_params_buffer, mali_c55_stats_buffer>;
> +                          MaliC55Params, mali_c55_stats_buffer>;
>  
>  } /* namespace ipa::mali_c55 */
>  
> diff --git a/src/ipa/mali-c55/params.h b/src/ipa/mali-c55/params.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..370f1b8b77bcf9ca5658ff75fca855b4c5f8467b
> --- /dev/null
> +++ b/src/ipa/mali-c55/params.h
> @@ -0,0 +1,77 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2025, Ideas On Board
> + *
> + * Mali C55 ISP Parameters
> + */
> +
> +#pragma once
> +
> +#include <linux/mali-c55-config.h>
> +#include <linux/videodev2.h>
> +
> +#include <libipa/v4l2_params.h>
> +
> +namespace libcamera {
> +
> +namespace ipa::mali_c55 {
> +
> +enum class MaliC55Blocks {
> +       Bls,
> +       AexpHist,
> +       AexpHistWeights,
> +       AexpIhist,
> +       AexpIhistWeights,
> +       Dgain,
> +       AwbGains,
> +       AwbConfig,
> +       MeshShadingConfig,
> +       MeshShadingSel,
> +};
> +
> +namespace details {
> +
> +template<MaliC55Blocks B>
> +struct block_type {
> +};
> +
> +#define MALI_C55_DEFINE_BLOCK_TYPE(id, cfgType, blkType)               \
> +template<>                                                             \
> +struct block_type<MaliC55Blocks::id> {                                 \
> +       using type = struct mali_c55_params_##cfgType;                  \
> +       static constexpr mali_c55_param_block_type blockType =          \
> +               mali_c55_param_block_type::MALI_C55_PARAM_##blkType;    \
> +}
> +
> +MALI_C55_DEFINE_BLOCK_TYPE(Bls,                        sensor_off_preshading,  BLOCK_SENSOR_OFFS);
> +MALI_C55_DEFINE_BLOCK_TYPE(AexpHist,           aexp_hist,              BLOCK_AEXP_HIST);
> +MALI_C55_DEFINE_BLOCK_TYPE(AexpHistWeights,    aexp_weights,           BLOCK_AEXP_HIST_WEIGHTS);
> +MALI_C55_DEFINE_BLOCK_TYPE(AexpIhist,          aexp_hist,              BLOCK_AEXP_IHIST);
> +MALI_C55_DEFINE_BLOCK_TYPE(AexpIhistWeights,   aexp_weights,           BLOCK_AEXP_IHIST_WEIGHTS);
> +MALI_C55_DEFINE_BLOCK_TYPE(Dgain,              digital_gain,           BLOCK_DIGITAL_GAIN);
> +MALI_C55_DEFINE_BLOCK_TYPE(AwbGains,           awb_gains,              BLOCK_AWB_GAINS);
> +MALI_C55_DEFINE_BLOCK_TYPE(AwbConfig,          awb_config,             BLOCK_AWB_CONFIG);
> +MALI_C55_DEFINE_BLOCK_TYPE(MeshShadingConfig,  mesh_shading_config,    MESH_SHADING_CONFIG);
> +MALI_C55_DEFINE_BLOCK_TYPE(MeshShadingSel,     mesh_shading_selection, MESH_SHADING_SELECTION);
> +
> +struct param_traits {
> +       using id_type = MaliC55Blocks;
> +
> +       template<id_type Id>
> +       using id_to_details = block_type<Id>;
> +};
> +
> +} /* namespace details */
> +
> +class MaliC55Params : public V4L2Params<details::param_traits>
> +{
> +public:
> +       MaliC55Params(Span<uint8_t> data)
> +               : V4L2Params(data, V4L2_ISP_PARAMS_VERSION_V1)
> +       {
> +       }
> +};
> +
> +} /* namespace ipa::mali_c55 */
> +
> +} /* namespace libcamera */
> 
> -- 
> 2.52.0
>

Patch
diff mbox series

diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp
index 78e7e07b2348a711e6261bac45e006f49a59513a..5d60cd8c9ff8a90e2e48e5d6939b538135b7ec3d 100644
--- a/src/ipa/mali-c55/algorithms/agc.cpp
+++ b/src/ipa/mali-c55/algorithms/agc.cpp
@@ -241,8 +241,8 @@  void Agc::queueRequest(IPAContext &context, const uint32_t frame,
 	}
 }
 
-size_t Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContext,
-			       mali_c55_params_block block)
+void Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContext,
+			     MaliC55Params *params)
 {
 	IPAActiveState &activeState = context.activeState;
 	double gain;
@@ -252,52 +252,50 @@  size_t Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContex
 	else
 		gain = activeState.agc.manual.ispGain;
 
-	block.header->type = MALI_C55_PARAM_BLOCK_DIGITAL_GAIN;
-	block.header->flags = 0;
-	block.header->size = sizeof(struct mali_c55_params_digital_gain);
+	auto block = params->block<MaliC55Blocks::Dgain>();
+	block->gain = floatingToFixedPoint<5, 8, uint16_t, double>(gain);
 
-	block.digital_gain->gain = floatingToFixedPoint<5, 8, uint16_t, double>(gain);
 	frameContext.agc.ispGain = gain;
-
-	return block.header->size;
 }
 
-size_t Agc::fillParamsBuffer(mali_c55_params_block block,
-			     enum mali_c55_param_block_type type)
+void Agc::fillParamsBuffer(MaliC55Params *params, enum MaliC55Blocks type)
 {
-	block.header->type = type;
-	block.header->flags = 0;
-	block.header->size = sizeof(struct mali_c55_params_aexp_hist);
+
+	assert(type == MaliC55Blocks::AexpHist || type == MaliC55Blocks::AexpIhist);
+
+	auto block = type == MaliC55Blocks::AexpHist ?
+			params->block<MaliC55Blocks::AexpHist>() :
+			params->block<MaliC55Blocks::AexpIhist>();
 
 	/* Collect every 3rd pixel horizontally */
-	block.aexp_hist->skip_x = 1;
+	block->skip_x = 1;
 	/* Start from first column */
-	block.aexp_hist->offset_x = 0;
+	block->offset_x = 0;
 	/* Collect every pixel vertically */
-	block.aexp_hist->skip_y = 0;
+	block->skip_y = 0;
 	/* Start from the first row */
-	block.aexp_hist->offset_y = 0;
+	block->offset_y = 0;
 	/* 1x scaling (i.e. none) */
-	block.aexp_hist->scale_bottom = 0;
-	block.aexp_hist->scale_top = 0;
+	block->scale_bottom = 0;
+	block->scale_top = 0;
 	/* Collect all Bayer planes into 4 separate histograms */
-	block.aexp_hist->plane_mode = 1;
+	block->plane_mode = 1;
 	/* Tap the data immediately after the digital gain block */
-	block.aexp_hist->tap_point = MALI_C55_AEXP_HIST_TAP_FS;
-
-	return block.header->size;
+	block->tap_point = MALI_C55_AEXP_HIST_TAP_FS;
 }
 
-size_t Agc::fillWeightsArrayBuffer(mali_c55_params_block block,
-				   enum mali_c55_param_block_type type)
+void Agc::fillWeightsArrayBuffer(MaliC55Params *params, const enum MaliC55Blocks type)
 {
-	block.header->type = type;
-	block.header->flags = 0;
-	block.header->size = sizeof(struct mali_c55_params_aexp_weights);
+	assert(type == MaliC55Blocks::AexpHistWeights ||
+	       type == MaliC55Blocks::AexpIhistWeights);
+
+	auto block = type == MaliC55Blocks::AexpHistWeights ?
+			params->block<MaliC55Blocks::AexpHistWeights>() :
+			params->block<MaliC55Blocks::AexpIhistWeights>();
 
 	/* We use every zone - a 15x15 grid */
-	block.aexp_weights->nodes_used_horiz = 15;
-	block.aexp_weights->nodes_used_vert = 15;
+	block->nodes_used_horiz = 15;
+	block->nodes_used_vert = 15;
 
 	/*
 	 * We uniformly weight the zones to 1 - this results in the collected
@@ -305,40 +303,25 @@  size_t Agc::fillWeightsArrayBuffer(mali_c55_params_block block,
 	 * approximate colour channel averages for the image.
 	 */
 	Span<uint8_t> weights{
-		block.aexp_weights->zone_weights,
+		block->zone_weights,
 		MALI_C55_MAX_ZONES
 	};
 	std::fill(weights.begin(), weights.end(), 1);
-
-	return block.header->size;
 }
 
 void Agc::prepare(IPAContext &context, const uint32_t frame,
-		  IPAFrameContext &frameContext, v4l2_isp_params_buffer *params)
+		  IPAFrameContext &frameContext, MaliC55Params *params)
 {
-	mali_c55_params_block block;
-
-	block.data = &params->data[params->data_size];
-	params->data_size += fillGainParamBlock(context, frameContext, block);
+	fillGainParamBlock(context, frameContext, params);
 
 	if (frame > 0)
 		return;
 
-	block.data = &params->data[params->data_size];
-	params->data_size += fillParamsBuffer(block,
-					       MALI_C55_PARAM_BLOCK_AEXP_HIST);
-
-	block.data = &params->data[params->data_size];
-	params->data_size += fillWeightsArrayBuffer(block,
-						     MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS);
-
-	block.data = &params->data[params->data_size];
-	params->data_size += fillParamsBuffer(block,
-					       MALI_C55_PARAM_BLOCK_AEXP_IHIST);
+	fillParamsBuffer(params, MaliC55Blocks::AexpHist);
+	fillWeightsArrayBuffer(params, MaliC55Blocks::AexpHistWeights);
 
-	block.data = &params->data[params->data_size];
-	params->data_size += fillWeightsArrayBuffer(block,
-						     MALI_C55_PARAM_BLOCK_AEXP_IHIST_WEIGHTS);
+	fillParamsBuffer(params, MaliC55Blocks::AexpIhist);
+	fillWeightsArrayBuffer(params, MaliC55Blocks::AexpIhistWeights);
 }
 
 double Agc::estimateLuminance(const double gain) const
diff --git a/src/ipa/mali-c55/algorithms/agc.h b/src/ipa/mali-c55/algorithms/agc.h
index 4325ef5a9b7dcef36107b64a65db993f194d4167..9684fff664bc67d287bb00f8dc88e238d8dd0cea 100644
--- a/src/ipa/mali-c55/algorithms/agc.h
+++ b/src/ipa/mali-c55/algorithms/agc.h
@@ -57,7 +57,7 @@  public:
 			  const ControlList &controls) override;
 	void prepare(IPAContext &context, const uint32_t frame,
 		     IPAFrameContext &frameContext,
-		     v4l2_isp_params_buffer *params) override;
+		     MaliC55Params *params) override;
 	void process(IPAContext &context, const uint32_t frame,
 		     IPAFrameContext &frameContext,
 		     const mali_c55_stats_buffer *stats,
@@ -65,13 +65,11 @@  public:
 
 private:
 	double estimateLuminance(const double gain) const override;
-	size_t fillGainParamBlock(IPAContext &context,
-				  IPAFrameContext &frameContext,
-				  mali_c55_params_block block);
-	size_t fillParamsBuffer(mali_c55_params_block block,
-				enum mali_c55_param_block_type type);
-	size_t fillWeightsArrayBuffer(mali_c55_params_block block,
-				      enum mali_c55_param_block_type type);
+	void fillGainParamBlock(IPAContext &context,
+				IPAFrameContext &frameContext,
+				MaliC55Params *params);
+	void fillParamsBuffer(MaliC55Params *params, enum MaliC55Blocks type);
+	void fillWeightsArrayBuffer(MaliC55Params *params, enum MaliC55Blocks type);
 
 	AgcStatistics statistics_;
 };
diff --git a/src/ipa/mali-c55/algorithms/awb.cpp b/src/ipa/mali-c55/algorithms/awb.cpp
index 694c0aaa9c6804bb58e380ba9c744f11c39224fe..964e810882a93cce02f991675d74bbf163d51e7c 100644
--- a/src/ipa/mali-c55/algorithms/awb.cpp
+++ b/src/ipa/mali-c55/algorithms/awb.cpp
@@ -43,13 +43,9 @@  int Awb::configure([[maybe_unused]] IPAContext &context,
 	return 0;
 }
 
-size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context,
+void Awb::fillGainsParamBlock(MaliC55Params *params, IPAContext &context,
 				IPAFrameContext &frameContext)
 {
-	block.header->type = MALI_C55_PARAM_BLOCK_AWB_GAINS;
-	block.header->flags = 0;
-	block.header->size = sizeof(struct mali_c55_params_awb_gains);
-
 	double rGain = context.activeState.awb.rGain;
 	double bGain = context.activeState.awb.bGain;
 
@@ -63,34 +59,32 @@  size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context
 	 * This holds true regardless of the bayer order of the input data, as
 	 * the mapping is done internally in the ISP.
 	 */
-	block.awb_gains->gain00 = floatingToFixedPoint<4, 8, uint16_t, double>(rGain);
-	block.awb_gains->gain01 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);
-	block.awb_gains->gain10 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);
-	block.awb_gains->gain11 = floatingToFixedPoint<4, 8, uint16_t, double>(bGain);
+	auto block = params->block<MaliC55Blocks::AwbGains>();
+
+	block->gain00 = floatingToFixedPoint<4, 8, uint16_t, double>(rGain);
+	block->gain01 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);
+	block->gain10 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);
+	block->gain11 = floatingToFixedPoint<4, 8, uint16_t, double>(bGain);
 
 	frameContext.awb.rGain = rGain;
 	frameContext.awb.bGain = bGain;
-
-	return sizeof(struct mali_c55_params_awb_gains);
 }
 
-size_t Awb::fillConfigParamBlock(mali_c55_params_block block)
+void Awb::fillConfigParamBlock(MaliC55Params *params)
 {
-	block.header->type = MALI_C55_PARAM_BLOCK_AWB_CONFIG;
-	block.header->flags = 0;
-	block.header->size = sizeof(struct mali_c55_params_awb_config);
+	auto block = params->block<MaliC55Blocks::AwbConfig>();
 
 	/* Tap the stats after the purple fringe block */
-	block.awb_config->tap_point = MALI_C55_AWB_STATS_TAP_PF;
+	block->tap_point = MALI_C55_AWB_STATS_TAP_PF;
 
 	/* Get R/G and B/G ratios as statistics */
-	block.awb_config->stats_mode = MALI_C55_AWB_MODE_RGBG;
+	block->stats_mode = MALI_C55_AWB_MODE_RGBG;
 
 	/* Default white level */
-	block.awb_config->white_level = 1023;
+	block->white_level = 1023;
 
 	/* Default black level */
-	block.awb_config->black_level = 0;
+	block->black_level = 0;
 
 	/*
 	 * By default pixels are included who's colour ratios are bounded in a
@@ -104,40 +98,34 @@  size_t Awb::fillConfigParamBlock(mali_c55_params_block block)
 	 *
 	 * \todo should these perhaps be tunable?
 	 */
-	block.awb_config->cr_max = 511;
-	block.awb_config->cr_min = 64;
-	block.awb_config->cb_max = 511;
-	block.awb_config->cb_min = 64;
+	block->cr_max = 511;
+	block->cr_min = 64;
+	block->cb_max = 511;
+	block->cb_min = 64;
 
 	/* We use the full 15x15 zoning scheme */
-	block.awb_config->nodes_used_horiz = 15;
-	block.awb_config->nodes_used_vert = 15;
+	block->nodes_used_horiz = 15;
+	block->nodes_used_vert = 15;
 
 	/*
 	 * We set the trimming boundaries equivalent to the main boundaries. In
 	 * other words; no trimming.
 	 */
-	block.awb_config->cr_high = 511;
-	block.awb_config->cr_low = 64;
-	block.awb_config->cb_high = 511;
-	block.awb_config->cb_low = 64;
-
-	return sizeof(struct mali_c55_params_awb_config);
+	block->cr_high = 511;
+	block->cr_low = 64;
+	block->cb_high = 511;
+	block->cb_low = 64;
 }
 
 void Awb::prepare(IPAContext &context, const uint32_t frame,
-		  IPAFrameContext &frameContext, v4l2_isp_params_buffer *params)
+		  IPAFrameContext &frameContext, MaliC55Params *params)
 {
-	mali_c55_params_block block;
-	block.data = &params->data[params->data_size];
-
-	params->data_size += fillGainsParamBlock(block, context, frameContext);
+	fillGainsParamBlock(params, context, frameContext);
 
 	if (frame > 0)
 		return;
 
-	block.data = &params->data[params->data_size];
-	params->data_size += fillConfigParamBlock(block);
+	fillConfigParamBlock(params);
 }
 
 void Awb::process(IPAContext &context, const uint32_t frame,
diff --git a/src/ipa/mali-c55/algorithms/awb.h b/src/ipa/mali-c55/algorithms/awb.h
index 647525ff700e8281e3cce63e64ba56a91294bcc2..683a62af263a14d2f5d5b261448953ada6669b2f 100644
--- a/src/ipa/mali-c55/algorithms/awb.h
+++ b/src/ipa/mali-c55/algorithms/awb.h
@@ -22,17 +22,17 @@  public:
 		      const IPACameraSensorInfo &configInfo) override;
 	void prepare(IPAContext &context, const uint32_t frame,
 		     IPAFrameContext &frameContext,
-		     v4l2_isp_params_buffer *params) override;
+		     MaliC55Params *params) override;
 	void process(IPAContext &context, const uint32_t frame,
 		     IPAFrameContext &frameContext,
 		     const mali_c55_stats_buffer *stats,
 		     ControlList &metadata) override;
 
 private:
-	size_t fillGainsParamBlock(mali_c55_params_block block,
-				   IPAContext &context,
-				   IPAFrameContext &frameContext);
-	size_t fillConfigParamBlock(mali_c55_params_block block);
+	void fillGainsParamBlock(MaliC55Params *params,
+				 IPAContext &context,
+				 IPAFrameContext &frameContext);
+	void fillConfigParamBlock(MaliC55Params *params);
 };
 
 } /* namespace ipa::mali_c55::algorithms */
diff --git a/src/ipa/mali-c55/algorithms/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp
index 543ba96cb57ac0cca2b8f822180d8d8b42f21fc7..d099219c3e43ec96fa452ed13fa46ada2025edc9 100644
--- a/src/ipa/mali-c55/algorithms/blc.cpp
+++ b/src/ipa/mali-c55/algorithms/blc.cpp
@@ -85,27 +85,19 @@  int BlackLevelCorrection::configure(IPAContext &context,
 void BlackLevelCorrection::prepare([[maybe_unused]] IPAContext &context,
 				   const uint32_t frame,
 				   [[maybe_unused]] IPAFrameContext &frameContext,
-				   v4l2_isp_params_buffer *params)
+				   MaliC55Params *params)
 {
-	mali_c55_params_block block;
-	block.data = &params->data[params->data_size];
-
 	if (frame > 0)
 		return;
 
 	if (!tuningParameters_)
 		return;
 
-	block.header->type = MALI_C55_PARAM_BLOCK_SENSOR_OFFS;
-	block.header->flags = 0;
-	block.header->size = sizeof(mali_c55_params_sensor_off_preshading);
-
-	block.sensor_offs->chan00 = offset00;
-	block.sensor_offs->chan01 = offset01;
-	block.sensor_offs->chan10 = offset10;
-	block.sensor_offs->chan11 = offset11;
-
-	params->data_size += block.header->size;
+	auto block = params->block<MaliC55Blocks::Bls>();
+	block->chan00 = offset00;
+	block->chan01 = offset01;
+	block->chan10 = offset10;
+	block->chan11 = offset11;
 }
 
 void BlackLevelCorrection::process([[maybe_unused]] IPAContext &context,
diff --git a/src/ipa/mali-c55/algorithms/blc.h b/src/ipa/mali-c55/algorithms/blc.h
index ee6c889ed89ac2230b231cb58a9fe4412c0ce164..fc5a7ea310cbdbcf271eb26c73b17243aea744cd 100644
--- a/src/ipa/mali-c55/algorithms/blc.h
+++ b/src/ipa/mali-c55/algorithms/blc.h
@@ -6,6 +6,7 @@ 
  */
 
 #include "algorithm.h"
+#include "params.h"
 
 namespace libcamera {
 
@@ -22,7 +23,7 @@  public:
 		      const IPACameraSensorInfo &configInfo) override;
 	void prepare(IPAContext &context, const uint32_t frame,
 		     IPAFrameContext &frameContext,
-		     v4l2_isp_params_buffer *params) override;
+		     MaliC55Params *params) override;
 	void process(IPAContext &context, const uint32_t frame,
 		     IPAFrameContext &frameContext,
 		     const mali_c55_stats_buffer *stats,
diff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp
index cb915c5efd3c22952035f2b03ee659f293942ec9..5b042c757bc70fe4eb4a5aaa848266b3afce9100 100644
--- a/src/ipa/mali-c55/algorithms/lsc.cpp
+++ b/src/ipa/mali-c55/algorithms/lsc.cpp
@@ -108,41 +108,33 @@  int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData
 	return 0;
 }
 
-size_t Lsc::fillConfigParamsBlock(mali_c55_params_block block) const
+void Lsc::fillConfigParamsBlock(MaliC55Params *params) const
 {
-	block.header->type = MALI_C55_PARAM_MESH_SHADING_CONFIG;
-	block.header->flags = 0;
-	block.header->size = sizeof(struct mali_c55_params_mesh_shading_config);
+	auto block = params->block<MaliC55Blocks::MeshShadingConfig>();
 
-	block.shading_config->mesh_show = false;
-	block.shading_config->mesh_scale = meshScale_;
-	block.shading_config->mesh_page_r = 0;
-	block.shading_config->mesh_page_g = 1;
-	block.shading_config->mesh_page_b = 2;
-	block.shading_config->mesh_width = meshSize_;
-	block.shading_config->mesh_height = meshSize_;
+	block->mesh_show = false;
+	block->mesh_scale = meshScale_;
+	block->mesh_page_r = 0;
+	block->mesh_page_g = 1;
+	block->mesh_page_b = 2;
+	block->mesh_width = meshSize_;
+	block->mesh_height = meshSize_;
 
-	std::copy(mesh_.begin(), mesh_.end(), block.shading_config->mesh);
-
-	return block.header->size;
+	std::copy(mesh_.begin(), mesh_.end(), block->mesh);
 }
 
-size_t Lsc::fillSelectionParamsBlock(mali_c55_params_block block, uint8_t bank,
+void Lsc::fillSelectionParamsBlock(MaliC55Params *params, uint8_t bank,
 				     uint8_t alpha) const
 {
-	block.header->type = MALI_C55_PARAM_MESH_SHADING_SELECTION;
-	block.header->flags = 0;
-	block.header->size = sizeof(struct mali_c55_params_mesh_shading_selection);
-
-	block.shading_selection->mesh_alpha_bank_r = bank;
-	block.shading_selection->mesh_alpha_bank_g = bank;
-	block.shading_selection->mesh_alpha_bank_b = bank;
-	block.shading_selection->mesh_alpha_r = alpha;
-	block.shading_selection->mesh_alpha_g = alpha;
-	block.shading_selection->mesh_alpha_b = alpha;
-	block.shading_selection->mesh_strength = 0x1000; /* Otherwise known as 1.0 */
-
-	return block.header->size;
+	auto block = params->block<MaliC55Blocks::MeshShadingSel>();
+
+	block->mesh_alpha_bank_r = bank;
+	block->mesh_alpha_bank_g = bank;
+	block->mesh_alpha_bank_b = bank;
+	block->mesh_alpha_r = alpha;
+	block->mesh_alpha_g = alpha;
+	block->mesh_alpha_b = alpha;
+	block->mesh_strength = 0x1000; /* Otherwise known as 1.0 */
 }
 
 std::tuple<uint8_t, uint8_t> Lsc::findBankAndAlpha(uint32_t ct) const
@@ -170,7 +162,7 @@  std::tuple<uint8_t, uint8_t> Lsc::findBankAndAlpha(uint32_t ct) const
 
 void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
 		  [[maybe_unused]] IPAFrameContext &frameContext,
-		  v4l2_isp_params_buffer *params)
+		  MaliC55Params *params)
 {
 	/*
 	 * For each frame we assess the colour temperature of the **last** frame
@@ -193,10 +185,7 @@  void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
 		std::tie(bank, alpha) = findBankAndAlpha(temperatureK);
 	}
 
-	mali_c55_params_block block;
-	block.data = &params->data[params->data_size];
-
-	params->data_size += fillSelectionParamsBlock(block, bank, alpha);
+	fillSelectionParamsBlock(params, bank, alpha);
 
 	if (frame > 0)
 		return;
@@ -205,8 +194,7 @@  void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
 	 * If this is the first frame, we need to load the parsed coefficient
 	 * tables from tuning data to the ISP.
 	 */
-	block.data = &params->data[params->data_size];
-	params->data_size += fillConfigParamsBlock(block);
+	fillConfigParamsBlock(params);
 }
 
 REGISTER_IPA_ALGORITHM(Lsc, "Lsc")
diff --git a/src/ipa/mali-c55/algorithms/lsc.h b/src/ipa/mali-c55/algorithms/lsc.h
index c287900502528ca82ab6c62d732b6ffc28ad8df6..e7092bc74a0b0301463167d16e1e888696547d10 100644
--- a/src/ipa/mali-c55/algorithms/lsc.h
+++ b/src/ipa/mali-c55/algorithms/lsc.h
@@ -23,15 +23,15 @@  public:
 	int init(IPAContext &context, const YamlObject &tuningData) override;
 	void prepare(IPAContext &context, const uint32_t frame,
 		     IPAFrameContext &frameContext,
-		     v4l2_isp_params_buffer *params) override;
+		     MaliC55Params *params) override;
 private:
 	static constexpr unsigned int kRedOffset = 0;
 	static constexpr unsigned int kGreenOffset = 1024;
 	static constexpr unsigned int kBlueOffset = 2048;
 
-	size_t fillConfigParamsBlock(mali_c55_params_block block) const;
-	size_t fillSelectionParamsBlock(mali_c55_params_block block,
-					uint8_t bank, uint8_t alpha) const;
+	void fillConfigParamsBlock(MaliC55Params *params) const;
+	void fillSelectionParamsBlock(MaliC55Params *params,
+				      uint8_t bank, uint8_t alpha) const;
 	std::tuple<uint8_t, uint8_t> findBankAndAlpha(uint32_t ct) const;
 
 	std::vector<uint32_t> mesh_ = std::vector<uint32_t>(3072);
diff --git a/src/ipa/mali-c55/mali-c55.cpp b/src/ipa/mali-c55/mali-c55.cpp
index 3f56604a0488dc853800ad54a54378166d7a112b..1d2a4f75cf8c7908ecebd02e71028d9f84ab1f94 100644
--- a/src/ipa/mali-c55/mali-c55.cpp
+++ b/src/ipa/mali-c55/mali-c55.cpp
@@ -30,6 +30,7 @@ 
 #include "libipa/camera_sensor_helper.h"
 
 #include "ipa_context.h"
+#include "params.h"
 
 namespace libcamera {
 
@@ -333,24 +334,13 @@  void IPAMaliC55::queueRequest(const uint32_t request, const ControlList &control
 void IPAMaliC55::fillParams(unsigned int request,
 			    [[maybe_unused]] uint32_t bufferId)
 {
-	struct v4l2_isp_params_buffer *params;
 	IPAFrameContext &frameContext = context_.frameContexts.get(request);
+	MaliC55Params params(buffers_.at(bufferId).planes()[0]);
 
-	params = reinterpret_cast<v4l2_isp_params_buffer *>(
-		buffers_.at(bufferId).planes()[0].data());
-	memset(params, 0,
-	       buffers_.at(bufferId).planes()[0].size());
-
-	params->version = V4L2_ISP_PARAMS_VERSION_V1;
-
-	for (auto const &algo : algorithms()) {
-		algo->prepare(context_, request, frameContext, params);
-
-		ASSERT(params->data_size <= MALI_C55_PARAMS_MAX_SIZE);
-	}
+	for (auto const &algo : algorithms())
+		algo->prepare(context_, request, frameContext, &params);
 
-	size_t bytesused = offsetof(struct v4l2_isp_params_buffer, data) + params->data_size;
-	paramsComputed.emit(request, bytesused);
+	paramsComputed.emit(request, params.bytesused());
 }
 
 void IPAMaliC55::processStats(unsigned int request, unsigned int bufferId,
diff --git a/src/ipa/mali-c55/module.h b/src/ipa/mali-c55/module.h
index a8dcb20841a4ebd7bde22cae4ff1f8eef530d8bb..13b34eb2839530a3518340165e6ca895d0f6bcaf 100644
--- a/src/ipa/mali-c55/module.h
+++ b/src/ipa/mali-c55/module.h
@@ -14,13 +14,14 @@ 
 #include <libipa/module.h>
 
 #include "ipa_context.h"
+#include "params.h"
 
 namespace libcamera {
 
 namespace ipa::mali_c55 {
 
 using Module = ipa::Module<IPAContext, IPAFrameContext, IPACameraSensorInfo,
-			   v4l2_isp_params_buffer, mali_c55_stats_buffer>;
+			   MaliC55Params, mali_c55_stats_buffer>;
 
 } /* namespace ipa::mali_c55 */
 
diff --git a/src/ipa/mali-c55/params.h b/src/ipa/mali-c55/params.h
new file mode 100644
index 0000000000000000000000000000000000000000..370f1b8b77bcf9ca5658ff75fca855b4c5f8467b
--- /dev/null
+++ b/src/ipa/mali-c55/params.h
@@ -0,0 +1,77 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2025, Ideas On Board
+ *
+ * Mali C55 ISP Parameters
+ */
+
+#pragma once
+
+#include <linux/mali-c55-config.h>
+#include <linux/videodev2.h>
+
+#include <libipa/v4l2_params.h>
+
+namespace libcamera {
+
+namespace ipa::mali_c55 {
+
+enum class MaliC55Blocks {
+	Bls,
+	AexpHist,
+	AexpHistWeights,
+	AexpIhist,
+	AexpIhistWeights,
+	Dgain,
+	AwbGains,
+	AwbConfig,
+	MeshShadingConfig,
+	MeshShadingSel,
+};
+
+namespace details {
+
+template<MaliC55Blocks B>
+struct block_type {
+};
+
+#define MALI_C55_DEFINE_BLOCK_TYPE(id, cfgType, blkType)		\
+template<>								\
+struct block_type<MaliC55Blocks::id> {					\
+	using type = struct mali_c55_params_##cfgType;			\
+	static constexpr mali_c55_param_block_type blockType = 		\
+		mali_c55_param_block_type::MALI_C55_PARAM_##blkType;	\
+}
+
+MALI_C55_DEFINE_BLOCK_TYPE(Bls,			sensor_off_preshading,	BLOCK_SENSOR_OFFS);
+MALI_C55_DEFINE_BLOCK_TYPE(AexpHist,		aexp_hist,		BLOCK_AEXP_HIST);
+MALI_C55_DEFINE_BLOCK_TYPE(AexpHistWeights,	aexp_weights,		BLOCK_AEXP_HIST_WEIGHTS);
+MALI_C55_DEFINE_BLOCK_TYPE(AexpIhist,		aexp_hist,		BLOCK_AEXP_IHIST);
+MALI_C55_DEFINE_BLOCK_TYPE(AexpIhistWeights,	aexp_weights,		BLOCK_AEXP_IHIST_WEIGHTS);
+MALI_C55_DEFINE_BLOCK_TYPE(Dgain,		digital_gain,		BLOCK_DIGITAL_GAIN);
+MALI_C55_DEFINE_BLOCK_TYPE(AwbGains,		awb_gains,		BLOCK_AWB_GAINS);
+MALI_C55_DEFINE_BLOCK_TYPE(AwbConfig,		awb_config,		BLOCK_AWB_CONFIG);
+MALI_C55_DEFINE_BLOCK_TYPE(MeshShadingConfig,	mesh_shading_config,	MESH_SHADING_CONFIG);
+MALI_C55_DEFINE_BLOCK_TYPE(MeshShadingSel,	mesh_shading_selection,	MESH_SHADING_SELECTION);
+
+struct param_traits {
+	using id_type = MaliC55Blocks;
+
+	template<id_type Id>
+	using id_to_details = block_type<Id>;
+};
+
+} /* namespace details */
+
+class MaliC55Params : public V4L2Params<details::param_traits>
+{
+public:
+	MaliC55Params(Span<uint8_t> data)
+		: V4L2Params(data, V4L2_ISP_PARAMS_VERSION_V1)
+	{
+	}
+};
+
+} /* namespace ipa::mali_c55 */
+
+} /* namespace libcamera */