Show a patch.

GET /api/1.1/patches/24477/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 24477,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/24477/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/24477/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20250926-v4l2-params-v3-5-ee114782c1be@ideasonboard.com>",
    "date": "2025-09-26T14:39:37",
    "name": "[v3,5/5] ipa: mali-c55: Introduce MaliC55Params",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "d2a9a4c9f9ed0bfda5b849e7db6e8ffdc8088374",
    "submitter": {
        "id": 143,
        "url": "https://patchwork.libcamera.org/api/1.1/people/143/?format=api",
        "name": "Jacopo Mondi",
        "email": "jacopo.mondi@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/24477/mbox/",
    "series": [
        {
            "id": 5461,
            "url": "https://patchwork.libcamera.org/api/1.1/series/5461/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5461",
            "date": "2025-09-26T14:39:32",
            "name": "ipa: libipa: Introduce V4L2Params",
            "version": 3,
            "mbox": "https://patchwork.libcamera.org/series/5461/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/24477/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/24477/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>",
        "X-Original-To": "parsemail@patchwork.libcamera.org",
        "Delivered-To": "parsemail@patchwork.libcamera.org",
        "Received": [
            "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id F0FDBC328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 26 Sep 2025 14:40:06 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A26ED6B608;\n\tFri, 26 Sep 2025 16:40:04 +0200 (CEST)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B7BEB6B5F8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 26 Sep 2025 16:39:57 +0200 (CEST)",
            "from [192.168.1.100] (93-61-96-190.ip145.fastwebnet.it\n\t[93.61.96.190])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 3C798152D;\n\tFri, 26 Sep 2025 16:38:31 +0200 (CEST)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"u7im/3QZ\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1758897511;\n\tbh=vI0N+DyqacjJISp6qENr/0VSu9nG56sjWISRuOOKRrE=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=u7im/3QZmGgZmRPmKoBmRb4Gg9uaZG1/PPtU3r0+7/tXuy5FojogIm8iHzSOz6nk8\n\tj2nMbM7m1uJ4258ojn0AAwD+PdynVyBkq8OzLq5D0mH5hclaGZ8RWemuv5TMhqVDAf\n\tTuVOfAPTkQ61Llk1pwWroHkFFL52PWTlla5O5G14=",
        "From": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>",
        "Date": "Fri, 26 Sep 2025 16:39:37 +0200",
        "Subject": "[PATCH v3 5/5] ipa: mali-c55: Introduce MaliC55Params",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "7bit",
        "Message-Id": "<20250926-v4l2-params-v3-5-ee114782c1be@ideasonboard.com>",
        "References": "<20250926-v4l2-params-v3-0-ee114782c1be@ideasonboard.com>",
        "In-Reply-To": "<20250926-v4l2-params-v3-0-ee114782c1be@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>, \n\tAntoine Bouyer <antoine.bouyer@nxp.com>",
        "X-Mailer": "b4 0.14.2",
        "X-Developer-Signature": "v=1; a=openpgp-sha256; l=25052;\n\ti=jacopo.mondi@ideasonboard.com; h=from:subject:message-id;\n\tbh=vI0N+DyqacjJISp6qENr/0VSu9nG56sjWISRuOOKRrE=;\n\tb=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBo1qW2BQMiwT1ZDD+gIwmQHI4W6YcdV968DuOPo\n\tw8yixUScVaJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaNaltgAKCRByNAaPFqFW\n\tPDBHEAC6lXOSs8sWj0iFMp9FLcc1jdleLqeEWUkl1p/kQD2V6KHpKpPqBnKavJFXuTZQ2cfRxeF\n\tWuM93EF1RyGbauOficv0ARt7DNJ1GARXZh8VomCIc5y2u4MZ9nPJ/dyaUVoUs1IE8ezyzu+sAP6\n\t15abuR79aj8JKaSyf+nBt1vq406Abw74xw/dh/FUxurdLoURuiAvvOXjxTg2i53PlbjxFMn4Hmx\n\tKDfq2g5rnRIZYcEptKVVYe2Gnwwlb0HjnBWYjBqvQ49KV1r7jUZ7lfALQTaExreInEe2qXm6cE6\n\tiU5JoMKLe1YIEXTBqKaoVuDbXjkawFuY3cdeGPULzY4awO/iKbreRbvMSNyWDo1LoUfFYMd0jH3\n\tOFJUvsahz/HxkReOnHPpcaeNbBep2FbCN0TnoB02a7eBbCyVXh3XIF5Cty39FZ77S8CWrFI8HxJ\n\tsaf4/84iu8HLdrIztnTSBmJG1ruzVsDmESvpBvgrnfW7DoZkzfnhjRMjAzm95CvCjc8/QYUhVX2\n\thTDGiku15FMXBT6PXJITud6uM4SjQCuuuEcUJuOOXBA17+pUjkGyHXM00aXk1aOomv4WOnD9/pQ\n\tFTQ+XbTPoXCGtfT9bpnUPjIfHAUWLE6M68YX46ZTZiDPAdDSP0dAj+SGeGjy1NBjjhfzlLwJC3n\n\tgN70bAKDswsEfLQ==",
        "X-Developer-Key": "i=jacopo.mondi@ideasonboard.com; a=openpgp;\n\tfpr=72392EDC88144A65C701EA9BA5826A2587AD026B",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Implement MaliC55Params to derive from V4L2Params and use the new\nhelpers in the Mali C55 IPA algorithms implementation.\n\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\nTested-By: Antoine Bouyer <antoine.bouyer@nxp.com>\n---\n src/ipa/mali-c55/algorithms/agc.cpp | 87 +++++++++++++++----------------------\n src/ipa/mali-c55/algorithms/agc.h   | 14 +++---\n src/ipa/mali-c55/algorithms/awb.cpp | 64 +++++++++++----------------\n src/ipa/mali-c55/algorithms/awb.h   | 10 ++---\n src/ipa/mali-c55/algorithms/blc.cpp | 20 +++------\n src/ipa/mali-c55/algorithms/blc.h   |  3 +-\n src/ipa/mali-c55/algorithms/lsc.cpp | 58 ++++++++++---------------\n src/ipa/mali-c55/algorithms/lsc.h   |  8 ++--\n src/ipa/mali-c55/mali-c55.cpp       | 19 +++-----\n src/ipa/mali-c55/module.h           |  3 +-\n src/ipa/mali-c55/params.h           | 83 +++++++++++++++++++++++++++++++++++\n 11 files changed, 197 insertions(+), 172 deletions(-)",
    "diff": "diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp\nindex da47cf15be49327a592e850817f2863ab62cb404..5d60cd8c9ff8a90e2e48e5d6939b538135b7ec3d 100644\n--- a/src/ipa/mali-c55/algorithms/agc.cpp\n+++ b/src/ipa/mali-c55/algorithms/agc.cpp\n@@ -241,8 +241,8 @@ void Agc::queueRequest(IPAContext &context, const uint32_t frame,\n \t}\n }\n \n-size_t Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContext,\n-\t\t\t       mali_c55_params_block block)\n+void Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContext,\n+\t\t\t     MaliC55Params *params)\n {\n \tIPAActiveState &activeState = context.activeState;\n \tdouble gain;\n@@ -252,52 +252,50 @@ size_t Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContex\n \telse\n \t\tgain = activeState.agc.manual.ispGain;\n \n-\tblock.header->type = MALI_C55_PARAM_BLOCK_DIGITAL_GAIN;\n-\tblock.header->flags = 0;\n-\tblock.header->size = sizeof(struct mali_c55_params_digital_gain);\n+\tauto block = params->block<MaliC55Blocks::Dgain>();\n+\tblock->gain = floatingToFixedPoint<5, 8, uint16_t, double>(gain);\n \n-\tblock.digital_gain->gain = floatingToFixedPoint<5, 8, uint16_t, double>(gain);\n \tframeContext.agc.ispGain = gain;\n-\n-\treturn block.header->size;\n }\n \n-size_t Agc::fillParamsBuffer(mali_c55_params_block block,\n-\t\t\t     enum mali_c55_param_block_type type)\n+void Agc::fillParamsBuffer(MaliC55Params *params, enum MaliC55Blocks type)\n {\n-\tblock.header->type = type;\n-\tblock.header->flags = 0;\n-\tblock.header->size = sizeof(struct mali_c55_params_aexp_hist);\n+\n+\tassert(type == MaliC55Blocks::AexpHist || type == MaliC55Blocks::AexpIhist);\n+\n+\tauto block = type == MaliC55Blocks::AexpHist ?\n+\t\t\tparams->block<MaliC55Blocks::AexpHist>() :\n+\t\t\tparams->block<MaliC55Blocks::AexpIhist>();\n \n \t/* Collect every 3rd pixel horizontally */\n-\tblock.aexp_hist->skip_x = 1;\n+\tblock->skip_x = 1;\n \t/* Start from first column */\n-\tblock.aexp_hist->offset_x = 0;\n+\tblock->offset_x = 0;\n \t/* Collect every pixel vertically */\n-\tblock.aexp_hist->skip_y = 0;\n+\tblock->skip_y = 0;\n \t/* Start from the first row */\n-\tblock.aexp_hist->offset_y = 0;\n+\tblock->offset_y = 0;\n \t/* 1x scaling (i.e. none) */\n-\tblock.aexp_hist->scale_bottom = 0;\n-\tblock.aexp_hist->scale_top = 0;\n+\tblock->scale_bottom = 0;\n+\tblock->scale_top = 0;\n \t/* Collect all Bayer planes into 4 separate histograms */\n-\tblock.aexp_hist->plane_mode = 1;\n+\tblock->plane_mode = 1;\n \t/* Tap the data immediately after the digital gain block */\n-\tblock.aexp_hist->tap_point = MALI_C55_AEXP_HIST_TAP_FS;\n-\n-\treturn block.header->size;\n+\tblock->tap_point = MALI_C55_AEXP_HIST_TAP_FS;\n }\n \n-size_t Agc::fillWeightsArrayBuffer(mali_c55_params_block block,\n-\t\t\t\t   enum mali_c55_param_block_type type)\n+void Agc::fillWeightsArrayBuffer(MaliC55Params *params, const enum MaliC55Blocks type)\n {\n-\tblock.header->type = type;\n-\tblock.header->flags = 0;\n-\tblock.header->size = sizeof(struct mali_c55_params_aexp_weights);\n+\tassert(type == MaliC55Blocks::AexpHistWeights ||\n+\t       type == MaliC55Blocks::AexpIhistWeights);\n+\n+\tauto block = type == MaliC55Blocks::AexpHistWeights ?\n+\t\t\tparams->block<MaliC55Blocks::AexpHistWeights>() :\n+\t\t\tparams->block<MaliC55Blocks::AexpIhistWeights>();\n \n \t/* We use every zone - a 15x15 grid */\n-\tblock.aexp_weights->nodes_used_horiz = 15;\n-\tblock.aexp_weights->nodes_used_vert = 15;\n+\tblock->nodes_used_horiz = 15;\n+\tblock->nodes_used_vert = 15;\n \n \t/*\n \t * We uniformly weight the zones to 1 - this results in the collected\n@@ -305,40 +303,25 @@ size_t Agc::fillWeightsArrayBuffer(mali_c55_params_block block,\n \t * approximate colour channel averages for the image.\n \t */\n \tSpan<uint8_t> weights{\n-\t\tblock.aexp_weights->zone_weights,\n+\t\tblock->zone_weights,\n \t\tMALI_C55_MAX_ZONES\n \t};\n \tstd::fill(weights.begin(), weights.end(), 1);\n-\n-\treturn block.header->size;\n }\n \n void Agc::prepare(IPAContext &context, const uint32_t frame,\n-\t\t  IPAFrameContext &frameContext, v4l2_params_buffer *params)\n+\t\t  IPAFrameContext &frameContext, MaliC55Params *params)\n {\n-\tmali_c55_params_block block;\n-\n-\tblock.data = &params->data[params->data_size];\n-\tparams->data_size += fillGainParamBlock(context, frameContext, block);\n+\tfillGainParamBlock(context, frameContext, params);\n \n \tif (frame > 0)\n \t\treturn;\n \n-\tblock.data = &params->data[params->data_size];\n-\tparams->data_size += fillParamsBuffer(block,\n-\t\t\t\t\t       MALI_C55_PARAM_BLOCK_AEXP_HIST);\n-\n-\tblock.data = &params->data[params->data_size];\n-\tparams->data_size += fillWeightsArrayBuffer(block,\n-\t\t\t\t\t\t     MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS);\n-\n-\tblock.data = &params->data[params->data_size];\n-\tparams->data_size += fillParamsBuffer(block,\n-\t\t\t\t\t       MALI_C55_PARAM_BLOCK_AEXP_IHIST);\n+\tfillParamsBuffer(params, MaliC55Blocks::AexpHist);\n+\tfillWeightsArrayBuffer(params, MaliC55Blocks::AexpHistWeights);\n \n-\tblock.data = &params->data[params->data_size];\n-\tparams->data_size += fillWeightsArrayBuffer(block,\n-\t\t\t\t\t\t     MALI_C55_PARAM_BLOCK_AEXP_IHIST_WEIGHTS);\n+\tfillParamsBuffer(params, MaliC55Blocks::AexpIhist);\n+\tfillWeightsArrayBuffer(params, MaliC55Blocks::AexpIhistWeights);\n }\n \n double Agc::estimateLuminance(const double gain) const\ndiff --git a/src/ipa/mali-c55/algorithms/agc.h b/src/ipa/mali-c55/algorithms/agc.h\nindex 64caf99350c1d1835832311a94a88a2bfde5721c..9684fff664bc67d287bb00f8dc88e238d8dd0cea 100644\n--- a/src/ipa/mali-c55/algorithms/agc.h\n+++ b/src/ipa/mali-c55/algorithms/agc.h\n@@ -57,7 +57,7 @@ public:\n \t\t\t  const ControlList &controls) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\n \t\t     IPAFrameContext &frameContext,\n-\t\t     v4l2_params_buffer *params) override;\n+\t\t     MaliC55Params *params) override;\n \tvoid process(IPAContext &context, const uint32_t frame,\n \t\t     IPAFrameContext &frameContext,\n \t\t     const mali_c55_stats_buffer *stats,\n@@ -65,13 +65,11 @@ public:\n \n private:\n \tdouble estimateLuminance(const double gain) const override;\n-\tsize_t fillGainParamBlock(IPAContext &context,\n-\t\t\t\t  IPAFrameContext &frameContext,\n-\t\t\t\t  mali_c55_params_block block);\n-\tsize_t fillParamsBuffer(mali_c55_params_block block,\n-\t\t\t\tenum mali_c55_param_block_type type);\n-\tsize_t fillWeightsArrayBuffer(mali_c55_params_block block,\n-\t\t\t\t      enum mali_c55_param_block_type type);\n+\tvoid fillGainParamBlock(IPAContext &context,\n+\t\t\t\tIPAFrameContext &frameContext,\n+\t\t\t\tMaliC55Params *params);\n+\tvoid fillParamsBuffer(MaliC55Params *params, enum MaliC55Blocks type);\n+\tvoid fillWeightsArrayBuffer(MaliC55Params *params, enum MaliC55Blocks type);\n \n \tAgcStatistics statistics_;\n };\ndiff --git a/src/ipa/mali-c55/algorithms/awb.cpp b/src/ipa/mali-c55/algorithms/awb.cpp\nindex 6b2cbed9de1ebfe9a2466ebe999eceac44fe5deb..964e810882a93cce02f991675d74bbf163d51e7c 100644\n--- a/src/ipa/mali-c55/algorithms/awb.cpp\n+++ b/src/ipa/mali-c55/algorithms/awb.cpp\n@@ -43,13 +43,9 @@ int Awb::configure([[maybe_unused]] IPAContext &context,\n \treturn 0;\n }\n \n-size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context,\n+void Awb::fillGainsParamBlock(MaliC55Params *params, IPAContext &context,\n \t\t\t\tIPAFrameContext &frameContext)\n {\n-\tblock.header->type = MALI_C55_PARAM_BLOCK_AWB_GAINS;\n-\tblock.header->flags = 0;\n-\tblock.header->size = sizeof(struct mali_c55_params_awb_gains);\n-\n \tdouble rGain = context.activeState.awb.rGain;\n \tdouble bGain = context.activeState.awb.bGain;\n \n@@ -63,34 +59,32 @@ size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context\n \t * This holds true regardless of the bayer order of the input data, as\n \t * the mapping is done internally in the ISP.\n \t */\n-\tblock.awb_gains->gain00 = floatingToFixedPoint<4, 8, uint16_t, double>(rGain);\n-\tblock.awb_gains->gain01 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);\n-\tblock.awb_gains->gain10 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);\n-\tblock.awb_gains->gain11 = floatingToFixedPoint<4, 8, uint16_t, double>(bGain);\n+\tauto block = params->block<MaliC55Blocks::AwbGains>();\n+\n+\tblock->gain00 = floatingToFixedPoint<4, 8, uint16_t, double>(rGain);\n+\tblock->gain01 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);\n+\tblock->gain10 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);\n+\tblock->gain11 = floatingToFixedPoint<4, 8, uint16_t, double>(bGain);\n \n \tframeContext.awb.rGain = rGain;\n \tframeContext.awb.bGain = bGain;\n-\n-\treturn sizeof(struct mali_c55_params_awb_gains);\n }\n \n-size_t Awb::fillConfigParamBlock(mali_c55_params_block block)\n+void Awb::fillConfigParamBlock(MaliC55Params *params)\n {\n-\tblock.header->type = MALI_C55_PARAM_BLOCK_AWB_CONFIG;\n-\tblock.header->flags = 0;\n-\tblock.header->size = sizeof(struct mali_c55_params_awb_config);\n+\tauto block = params->block<MaliC55Blocks::AwbConfig>();\n \n \t/* Tap the stats after the purple fringe block */\n-\tblock.awb_config->tap_point = MALI_C55_AWB_STATS_TAP_PF;\n+\tblock->tap_point = MALI_C55_AWB_STATS_TAP_PF;\n \n \t/* Get R/G and B/G ratios as statistics */\n-\tblock.awb_config->stats_mode = MALI_C55_AWB_MODE_RGBG;\n+\tblock->stats_mode = MALI_C55_AWB_MODE_RGBG;\n \n \t/* Default white level */\n-\tblock.awb_config->white_level = 1023;\n+\tblock->white_level = 1023;\n \n \t/* Default black level */\n-\tblock.awb_config->black_level = 0;\n+\tblock->black_level = 0;\n \n \t/*\n \t * By default pixels are included who's colour ratios are bounded in a\n@@ -104,40 +98,34 @@ size_t Awb::fillConfigParamBlock(mali_c55_params_block block)\n \t *\n \t * \\todo should these perhaps be tunable?\n \t */\n-\tblock.awb_config->cr_max = 511;\n-\tblock.awb_config->cr_min = 64;\n-\tblock.awb_config->cb_max = 511;\n-\tblock.awb_config->cb_min = 64;\n+\tblock->cr_max = 511;\n+\tblock->cr_min = 64;\n+\tblock->cb_max = 511;\n+\tblock->cb_min = 64;\n \n \t/* We use the full 15x15 zoning scheme */\n-\tblock.awb_config->nodes_used_horiz = 15;\n-\tblock.awb_config->nodes_used_vert = 15;\n+\tblock->nodes_used_horiz = 15;\n+\tblock->nodes_used_vert = 15;\n \n \t/*\n \t * We set the trimming boundaries equivalent to the main boundaries. In\n \t * other words; no trimming.\n \t */\n-\tblock.awb_config->cr_high = 511;\n-\tblock.awb_config->cr_low = 64;\n-\tblock.awb_config->cb_high = 511;\n-\tblock.awb_config->cb_low = 64;\n-\n-\treturn sizeof(struct mali_c55_params_awb_config);\n+\tblock->cr_high = 511;\n+\tblock->cr_low = 64;\n+\tblock->cb_high = 511;\n+\tblock->cb_low = 64;\n }\n \n void Awb::prepare(IPAContext &context, const uint32_t frame,\n-\t\t  IPAFrameContext &frameContext, v4l2_params_buffer *params)\n+\t\t  IPAFrameContext &frameContext, MaliC55Params *params)\n {\n-\tmali_c55_params_block block;\n-\tblock.data = &params->data[params->data_size];\n-\n-\tparams->data_size += fillGainsParamBlock(block, context, frameContext);\n+\tfillGainsParamBlock(params, context, frameContext);\n \n \tif (frame > 0)\n \t\treturn;\n \n-\tblock.data = &params->data[params->data_size];\n-\tparams->data_size += fillConfigParamBlock(block);\n+\tfillConfigParamBlock(params);\n }\n \n void Awb::process(IPAContext &context, const uint32_t frame,\ndiff --git a/src/ipa/mali-c55/algorithms/awb.h b/src/ipa/mali-c55/algorithms/awb.h\nindex b5ff121041d1a01e3a51d64b87a90fb2e1d8dd10..683a62af263a14d2f5d5b261448953ada6669b2f 100644\n--- a/src/ipa/mali-c55/algorithms/awb.h\n+++ b/src/ipa/mali-c55/algorithms/awb.h\n@@ -22,17 +22,17 @@ public:\n \t\t      const IPACameraSensorInfo &configInfo) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\n \t\t     IPAFrameContext &frameContext,\n-\t\t     v4l2_params_buffer *params) override;\n+\t\t     MaliC55Params *params) override;\n \tvoid process(IPAContext &context, const uint32_t frame,\n \t\t     IPAFrameContext &frameContext,\n \t\t     const mali_c55_stats_buffer *stats,\n \t\t     ControlList &metadata) override;\n \n private:\n-\tsize_t fillGainsParamBlock(mali_c55_params_block block,\n-\t\t\t\t   IPAContext &context,\n-\t\t\t\t   IPAFrameContext &frameContext);\n-\tsize_t fillConfigParamBlock(mali_c55_params_block block);\n+\tvoid fillGainsParamBlock(MaliC55Params *params,\n+\t\t\t\t IPAContext &context,\n+\t\t\t\t IPAFrameContext &frameContext);\n+\tvoid fillConfigParamBlock(MaliC55Params *params);\n };\n \n } /* namespace ipa::mali_c55::algorithms */\ndiff --git a/src/ipa/mali-c55/algorithms/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp\nindex 8fd0f10c3082030a36a256830042d733ed4c8c78..d099219c3e43ec96fa452ed13fa46ada2025edc9 100644\n--- a/src/ipa/mali-c55/algorithms/blc.cpp\n+++ b/src/ipa/mali-c55/algorithms/blc.cpp\n@@ -85,27 +85,19 @@ int BlackLevelCorrection::configure(IPAContext &context,\n void BlackLevelCorrection::prepare([[maybe_unused]] IPAContext &context,\n \t\t\t\t   const uint32_t frame,\n \t\t\t\t   [[maybe_unused]] IPAFrameContext &frameContext,\n-\t\t\t\t   v4l2_params_buffer *params)\n+\t\t\t\t   MaliC55Params *params)\n {\n-\tmali_c55_params_block block;\n-\tblock.data = &params->data[params->data_size];\n-\n \tif (frame > 0)\n \t\treturn;\n \n \tif (!tuningParameters_)\n \t\treturn;\n \n-\tblock.header->type = MALI_C55_PARAM_BLOCK_SENSOR_OFFS;\n-\tblock.header->flags = 0;\n-\tblock.header->size = sizeof(mali_c55_params_sensor_off_preshading);\n-\n-\tblock.sensor_offs->chan00 = offset00;\n-\tblock.sensor_offs->chan01 = offset01;\n-\tblock.sensor_offs->chan10 = offset10;\n-\tblock.sensor_offs->chan11 = offset11;\n-\n-\tparams->data_size += block.header->size;\n+\tauto block = params->block<MaliC55Blocks::Bls>();\n+\tblock->chan00 = offset00;\n+\tblock->chan01 = offset01;\n+\tblock->chan10 = offset10;\n+\tblock->chan11 = offset11;\n }\n \n void BlackLevelCorrection::process([[maybe_unused]] IPAContext &context,\ndiff --git a/src/ipa/mali-c55/algorithms/blc.h b/src/ipa/mali-c55/algorithms/blc.h\nindex cf10505ce2908df0d5e658d3fdce663729c7ea76..fc5a7ea310cbdbcf271eb26c73b17243aea744cd 100644\n--- a/src/ipa/mali-c55/algorithms/blc.h\n+++ b/src/ipa/mali-c55/algorithms/blc.h\n@@ -6,6 +6,7 @@\n  */\n \n #include \"algorithm.h\"\n+#include \"params.h\"\n \n namespace libcamera {\n \n@@ -22,7 +23,7 @@ public:\n \t\t      const IPACameraSensorInfo &configInfo) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\n \t\t     IPAFrameContext &frameContext,\n-\t\t     v4l2_params_buffer *params) override;\n+\t\t     MaliC55Params *params) override;\n \tvoid process(IPAContext &context, const uint32_t frame,\n \t\t     IPAFrameContext &frameContext,\n \t\t     const mali_c55_stats_buffer *stats,\ndiff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp\nindex 35f1d876e60db252a45cadb771e541735749d106..5b042c757bc70fe4eb4a5aaa848266b3afce9100 100644\n--- a/src/ipa/mali-c55/algorithms/lsc.cpp\n+++ b/src/ipa/mali-c55/algorithms/lsc.cpp\n@@ -108,41 +108,33 @@ int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData\n \treturn 0;\n }\n \n-size_t Lsc::fillConfigParamsBlock(mali_c55_params_block block) const\n+void Lsc::fillConfigParamsBlock(MaliC55Params *params) const\n {\n-\tblock.header->type = MALI_C55_PARAM_MESH_SHADING_CONFIG;\n-\tblock.header->flags = 0;\n-\tblock.header->size = sizeof(struct mali_c55_params_mesh_shading_config);\n+\tauto block = params->block<MaliC55Blocks::MeshShadingConfig>();\n \n-\tblock.shading_config->mesh_show = false;\n-\tblock.shading_config->mesh_scale = meshScale_;\n-\tblock.shading_config->mesh_page_r = 0;\n-\tblock.shading_config->mesh_page_g = 1;\n-\tblock.shading_config->mesh_page_b = 2;\n-\tblock.shading_config->mesh_width = meshSize_;\n-\tblock.shading_config->mesh_height = meshSize_;\n+\tblock->mesh_show = false;\n+\tblock->mesh_scale = meshScale_;\n+\tblock->mesh_page_r = 0;\n+\tblock->mesh_page_g = 1;\n+\tblock->mesh_page_b = 2;\n+\tblock->mesh_width = meshSize_;\n+\tblock->mesh_height = meshSize_;\n \n-\tstd::copy(mesh_.begin(), mesh_.end(), block.shading_config->mesh);\n-\n-\treturn block.header->size;\n+\tstd::copy(mesh_.begin(), mesh_.end(), block->mesh);\n }\n \n-size_t Lsc::fillSelectionParamsBlock(mali_c55_params_block block, uint8_t bank,\n+void Lsc::fillSelectionParamsBlock(MaliC55Params *params, uint8_t bank,\n \t\t\t\t     uint8_t alpha) const\n {\n-\tblock.header->type = MALI_C55_PARAM_MESH_SHADING_SELECTION;\n-\tblock.header->flags = 0;\n-\tblock.header->size = sizeof(struct mali_c55_params_mesh_shading_selection);\n-\n-\tblock.shading_selection->mesh_alpha_bank_r = bank;\n-\tblock.shading_selection->mesh_alpha_bank_g = bank;\n-\tblock.shading_selection->mesh_alpha_bank_b = bank;\n-\tblock.shading_selection->mesh_alpha_r = alpha;\n-\tblock.shading_selection->mesh_alpha_g = alpha;\n-\tblock.shading_selection->mesh_alpha_b = alpha;\n-\tblock.shading_selection->mesh_strength = 0x1000; /* Otherwise known as 1.0 */\n-\n-\treturn block.header->size;\n+\tauto block = params->block<MaliC55Blocks::MeshShadingSel>();\n+\n+\tblock->mesh_alpha_bank_r = bank;\n+\tblock->mesh_alpha_bank_g = bank;\n+\tblock->mesh_alpha_bank_b = bank;\n+\tblock->mesh_alpha_r = alpha;\n+\tblock->mesh_alpha_g = alpha;\n+\tblock->mesh_alpha_b = alpha;\n+\tblock->mesh_strength = 0x1000; /* Otherwise known as 1.0 */\n }\n \n std::tuple<uint8_t, uint8_t> Lsc::findBankAndAlpha(uint32_t ct) const\n@@ -170,7 +162,7 @@ std::tuple<uint8_t, uint8_t> Lsc::findBankAndAlpha(uint32_t ct) const\n \n void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n \t\t  [[maybe_unused]] IPAFrameContext &frameContext,\n-\t\t  v4l2_params_buffer *params)\n+\t\t  MaliC55Params *params)\n {\n \t/*\n \t * For each frame we assess the colour temperature of the **last** frame\n@@ -193,10 +185,7 @@ void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n \t\tstd::tie(bank, alpha) = findBankAndAlpha(temperatureK);\n \t}\n \n-\tmali_c55_params_block block;\n-\tblock.data = &params->data[params->data_size];\n-\n-\tparams->data_size += fillSelectionParamsBlock(block, bank, alpha);\n+\tfillSelectionParamsBlock(params, bank, alpha);\n \n \tif (frame > 0)\n \t\treturn;\n@@ -205,8 +194,7 @@ void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n \t * If this is the first frame, we need to load the parsed coefficient\n \t * tables from tuning data to the ISP.\n \t */\n-\tblock.data = &params->data[params->data_size];\n-\tparams->data_size += fillConfigParamsBlock(block);\n+\tfillConfigParamsBlock(params);\n }\n \n REGISTER_IPA_ALGORITHM(Lsc, \"Lsc\")\ndiff --git a/src/ipa/mali-c55/algorithms/lsc.h b/src/ipa/mali-c55/algorithms/lsc.h\nindex 9019a61aa547e41154615eba88547d3eee1634e2..e7092bc74a0b0301463167d16e1e888696547d10 100644\n--- a/src/ipa/mali-c55/algorithms/lsc.h\n+++ b/src/ipa/mali-c55/algorithms/lsc.h\n@@ -23,15 +23,15 @@ public:\n \tint init(IPAContext &context, const YamlObject &tuningData) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\n \t\t     IPAFrameContext &frameContext,\n-\t\t     v4l2_params_buffer *params) override;\n+\t\t     MaliC55Params *params) override;\n private:\n \tstatic constexpr unsigned int kRedOffset = 0;\n \tstatic constexpr unsigned int kGreenOffset = 1024;\n \tstatic constexpr unsigned int kBlueOffset = 2048;\n \n-\tsize_t fillConfigParamsBlock(mali_c55_params_block block) const;\n-\tsize_t fillSelectionParamsBlock(mali_c55_params_block block,\n-\t\t\t\t\tuint8_t bank, uint8_t alpha) const;\n+\tvoid fillConfigParamsBlock(MaliC55Params *params) const;\n+\tvoid fillSelectionParamsBlock(MaliC55Params *params,\n+\t\t\t\t      uint8_t bank, uint8_t alpha) const;\n \tstd::tuple<uint8_t, uint8_t> findBankAndAlpha(uint32_t ct) const;\n \n \tstd::vector<uint32_t> mesh_ = std::vector<uint32_t>(3072);\ndiff --git a/src/ipa/mali-c55/mali-c55.cpp b/src/ipa/mali-c55/mali-c55.cpp\nindex a6d3e984a438c01509ed27469d9f20c25bc884cf..fe36d4445c3ac75abe48dbe2335fa1f3aded9609 100644\n--- a/src/ipa/mali-c55/mali-c55.cpp\n+++ b/src/ipa/mali-c55/mali-c55.cpp\n@@ -28,6 +28,7 @@\n #include \"libipa/camera_sensor_helper.h\"\n \n #include \"ipa_context.h\"\n+#include \"params.h\"\n \n namespace libcamera {\n \n@@ -331,23 +332,13 @@ void IPAMaliC55::queueRequest(const uint32_t request, const ControlList &control\n void IPAMaliC55::fillParams(unsigned int request,\n \t\t\t    [[maybe_unused]] uint32_t bufferId)\n {\n-\tstruct v4l2_params_buffer *params;\n \tIPAFrameContext &frameContext = context_.frameContexts.get(request);\n+\tMaliC55Params params(buffers_.at(bufferId).planes()[0]);\n \n-\tparams = reinterpret_cast<v4l2_params_buffer *>(\n-\t\tbuffers_.at(bufferId).planes()[0].data());\n-\tmemset(params, 0, sizeof(v4l2_params_buffer));\n-\n-\tparams->version = MALI_C55_PARAM_BUFFER_V1;\n-\n-\tfor (auto const &algo : algorithms()) {\n-\t\talgo->prepare(context_, request, frameContext, params);\n-\n-\t\tASSERT(params->data_size <= MALI_C55_PARAMS_MAX_SIZE);\n-\t}\n+\tfor (auto const &algo : algorithms())\n+\t\talgo->prepare(context_, request, frameContext, &params);\n \n-\tsize_t bytesused = offsetof(struct v4l2_params_buffer, data) + params->data_size;\n-\tparamsComputed.emit(request, bytesused);\n+\tparamsComputed.emit(request, params.size());\n }\n \n void IPAMaliC55::processStats(unsigned int request, unsigned int bufferId,\ndiff --git a/src/ipa/mali-c55/module.h b/src/ipa/mali-c55/module.h\nindex 434d2c585d2f4eb03402c57e87302fc82e82a0f0..13b34eb2839530a3518340165e6ca895d0f6bcaf 100644\n--- a/src/ipa/mali-c55/module.h\n+++ b/src/ipa/mali-c55/module.h\n@@ -14,13 +14,14 @@\n #include <libipa/module.h>\n \n #include \"ipa_context.h\"\n+#include \"params.h\"\n \n namespace libcamera {\n \n namespace ipa::mali_c55 {\n \n using Module = ipa::Module<IPAContext, IPAFrameContext, IPACameraSensorInfo,\n-\t\t\t   v4l2_params_buffer, mali_c55_stats_buffer>;\n+\t\t\t   MaliC55Params, mali_c55_stats_buffer>;\n \n } /* namespace ipa::mali_c55 */\n \ndiff --git a/src/ipa/mali-c55/params.h b/src/ipa/mali-c55/params.h\nnew file mode 100644\nindex 0000000000000000000000000000000000000000..bb26da19a8f1336eeed91989a6c13e7630c6e5f4\n--- /dev/null\n+++ b/src/ipa/mali-c55/params.h\n@@ -0,0 +1,83 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2025, Ideas On Board\n+ *\n+ * Mali C55 ISP Parameters\n+ */\n+\n+#pragma once\n+\n+#include <linux/mali-c55-config.h>\n+#include <linux/videodev2.h>\n+\n+#include <libipa/v4l2_params.h>\n+\n+namespace libcamera {\n+\n+namespace ipa::mali_c55 {\n+\n+enum class MaliC55Blocks {\n+\tBls,\n+\tAexpHist,\n+\tAexpHistWeights,\n+\tAexpIhist,\n+\tAexpIhistWeights,\n+\tDgain,\n+\tAwbGains,\n+\tAwbConfig,\n+\tMeshShadingConfig,\n+\tMeshShadingSel,\n+};\n+\n+namespace details {\n+\n+template<MaliC55Blocks B>\n+struct block_type {\n+};\n+\n+#define MALI_C55_DEFINE_BLOCK_TYPE(id, cfgType, blkType)\t\t\\\n+template<>\t\t\t\t\t\t\t\t\\\n+struct block_type<MaliC55Blocks::id> {\t\t\t\t\t\\\n+\tusing type = struct mali_c55_params_##cfgType;\t\t\t\\\n+\tstatic constexpr mali_c55_param_block_type blockType = \t\t\\\n+\t\tmali_c55_param_block_type::MALI_C55_PARAM_##blkType;\t\\\n+};\n+\n+MALI_C55_DEFINE_BLOCK_TYPE(Bls, sensor_off_preshading, BLOCK_SENSOR_OFFS)\n+MALI_C55_DEFINE_BLOCK_TYPE(AexpHist, aexp_hist, BLOCK_AEXP_HIST)\n+MALI_C55_DEFINE_BLOCK_TYPE(AexpHistWeights, aexp_weights,\n+\t\t\t   BLOCK_AEXP_HIST_WEIGHTS)\n+MALI_C55_DEFINE_BLOCK_TYPE(AexpIhist, aexp_hist, BLOCK_AEXP_IHIST)\n+MALI_C55_DEFINE_BLOCK_TYPE(AexpIhistWeights, aexp_weights,\n+\t\t\t   BLOCK_AEXP_IHIST_WEIGHTS)\n+MALI_C55_DEFINE_BLOCK_TYPE(Dgain, digital_gain, BLOCK_DIGITAL_GAIN)\n+MALI_C55_DEFINE_BLOCK_TYPE(AwbGains, awb_gains, BLOCK_AWB_GAINS)\n+MALI_C55_DEFINE_BLOCK_TYPE(AwbConfig, awb_config, BLOCK_AWB_CONFIG)\n+MALI_C55_DEFINE_BLOCK_TYPE(MeshShadingConfig, mesh_shading_config,\n+\t\t\t   MESH_SHADING_CONFIG)\n+MALI_C55_DEFINE_BLOCK_TYPE(MeshShadingSel, mesh_shading_selection,\n+\t\t\t   MESH_SHADING_SELECTION)\n+\n+struct param_traits {\n+\tusing id_type = MaliC55Blocks;\n+\n+\ttemplate<id_type Id>\n+\tusing id_to_details = block_type<Id>;\n+};\n+\n+} /* namespace details */\n+\n+class MaliC55Params : public V4L2Params<details::param_traits>\n+{\n+public:\n+\tstatic constexpr unsigned int kVersion = MALI_C55_PARAM_BUFFER_V1;\n+\n+\tMaliC55Params(Span<uint8_t> data)\n+\t\t: V4L2Params(data, kVersion)\n+\t{\n+\t}\n+};\n+\n+} /* namespace ipa::mali_c55 */\n+\n+} /* namespace libcamera */\n",
    "prefixes": [
        "v3",
        "5/5"
    ]
}