[4/4] ipa: mali-c55: Introduce MaliC55Params
diff mbox series

Message ID 20250829-v4l2-params-v1-4-340773fb69ff@ideasonboard.com
State New
Headers show
Series
  • ipa: libipa: Introduce V4L2Params
Related show

Commit Message

Jacopo Mondi Aug. 29, 2025, 11:54 a.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>
---
 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       | 19 +++-----
 src/ipa/mali-c55/module.h           |  3 +-
 src/ipa/mali-c55/params.h           | 89 +++++++++++++++++++++++++++++++++++++
 11 files changed, 203 insertions(+), 172 deletions(-)

Patch
diff mbox series

diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp
index 80d9d956d07d1665e61876b0429fb94a30c7cbe1..c1ed1cd78430e8ea0b3ea6998c7ee17e43ed777d 100644
--- a/src/ipa/mali-c55/algorithms/agc.cpp
+++ b/src/ipa/mali-c55/algorithms/agc.cpp
@@ -240,8 +240,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;
@@ -251,52 +251,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
@@ -304,40 +302,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_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 64caf99350c1d1835832311a94a88a2bfde5721c..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_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 6b2cbed9de1ebfe9a2466ebe999eceac44fe5deb..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_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 b5ff121041d1a01e3a51d64b87a90fb2e1d8dd10..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_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 8fd0f10c3082030a36a256830042d733ed4c8c78..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_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 cf10505ce2908df0d5e658d3fdce663729c7ea76..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_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 35f1d876e60db252a45cadb771e541735749d106..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_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 9019a61aa547e41154615eba88547d3eee1634e2..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_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 a6d3e984a438c01509ed27469d9f20c25bc884cf..fe36d4445c3ac75abe48dbe2335fa1f3aded9609 100644
--- a/src/ipa/mali-c55/mali-c55.cpp
+++ b/src/ipa/mali-c55/mali-c55.cpp
@@ -28,6 +28,7 @@ 
 #include "libipa/camera_sensor_helper.h"
 
 #include "ipa_context.h"
+#include "params.h"
 
 namespace libcamera {
 
@@ -331,23 +332,13 @@  void IPAMaliC55::queueRequest(const uint32_t request, const ControlList &control
 void IPAMaliC55::fillParams(unsigned int request,
 			    [[maybe_unused]] uint32_t bufferId)
 {
-	struct v4l2_params_buffer *params;
 	IPAFrameContext &frameContext = context_.frameContexts.get(request);
+	MaliC55Params params(buffers_.at(bufferId).planes()[0]);
 
-	params = reinterpret_cast<v4l2_params_buffer *>(
-		buffers_.at(bufferId).planes()[0].data());
-	memset(params, 0, sizeof(v4l2_params_buffer));
-
-	params->version = MALI_C55_PARAM_BUFFER_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_params_buffer, data) + params->data_size;
-	paramsComputed.emit(request, bytesused);
+	paramsComputed.emit(request, params.size());
 }
 
 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 434d2c585d2f4eb03402c57e87302fc82e82a0f0..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_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..1cc56dbad539ba6720f9b1e73c8339eb3bf885c7
--- /dev/null
+++ b/src/ipa/mali-c55/params.h
@@ -0,0 +1,89 @@ 
+/* 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)
+
+} /* namespace details */
+
+class MaliC55Params : public V4L2Params<MaliC55Blocks>
+{
+public:
+	static constexpr unsigned int kVersion = MALI_C55_PARAM_BUFFER_V1;
+
+	MaliC55Params(Span<uint8_t> data)
+		: V4L2Params<MaliC55Blocks>(data, kVersion)
+	{
+	}
+
+	template<MaliC55Blocks B>
+	auto block()
+	{
+		using Type = typename details::block_type<B>::type;
+
+		auto blockType = details::block_type<B>::blockType;
+		size_t blockSize = sizeof(Type);
+
+		auto data = V4L2Params::block(B, blockType, blockSize);
+
+		return V4L2ParamsBlock<Type>(data);
+	}
+};
+
+} /* namespace ipa::mali_c55 */
+
+} /* namespace libcamera */