From patchwork Fri Sep 26 14:39:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24473 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id BC393C328C for ; Fri, 26 Sep 2025 14:39:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 746D26B5F3; Fri, 26 Sep 2025 16:39:55 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="QZDyeVrz"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3DDF0613AB for ; Fri, 26 Sep 2025 16:39:52 +0200 (CEST) Received: from [192.168.1.100] (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6460C152D; Fri, 26 Sep 2025 16:38:26 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758897507; bh=m6UKSto21lH4DyPU8izBwOOwuVC+d0tBZtGMWkTJvDE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=QZDyeVrzlgziccQ1ro0uKnlr5nze1VJSD91GyxQR9VVfMp4Qt8XcJDqCQPzM1TtEm p1hBs7UFHo7Y++ico7226kEs/aGuVwdGhDyQd5Ip3NjWT/TK85UsMjhRas8LM+0GS8 YLlL9mz70BPJqylK8nHAErEZtPKnmFIAfQln3A8Q= From: Jacopo Mondi Date: Fri, 26 Sep 2025 16:39:33 +0200 Subject: [PATCH v3 1/5] include: linux: Add v4l2-isp.h MIME-Version: 1.0 Message-Id: <20250926-v4l2-params-v3-1-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 , Antoine Bouyer X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=5197; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=m6UKSto21lH4DyPU8izBwOOwuVC+d0tBZtGMWkTJvDE=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBo1qW1PefG/KS8EOG9GuujipETtTGDC/87e9eGe t4FQKMqohWJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaNaltQAKCRByNAaPFqFW PExDD/9ybPiCorsBq40xtxgb1NjjlpRkRKWHdqrS+i1G68w+MGC/C+BTxz0V0bjpp68MxWpBycP Cf2ZxtRNSzcmXwpsT9GKCUIDfL3Wi98e+dbUDuu9HDZhyhKvigQf/KySwT4c8mljs1BZl4iP6Rm 5pbAioe5HBhPPxvZjpq5pM12zEBEkCYGfd6QrbSIYoLq6ZvIcxvtOpE6jb8BQJt7sfdjrtUMyae HzNxfJ+gPpqDtSRYSRlHlqDQCIJjeS/kLzlUc5Fo7cTzj/FEMRdBrZ0PpBsbzoy20TsGG0ekG6o OjgcAKnkwKqmHeymyTKUK44rImgBWCWQYujlphL5vrH5YjQIUVe2+WGd6pa6mPEBT/msfxZR3io dxST47DMIW67HC/EX/ImZ41m2tv1Drd/FCMERAa5P9KsaO59S5txH4vsEPHYCnV/d9a0V1psCea 1eFo3X2OXNsPljCcP2fAP2jilsqOMBvu5SkKNg5t6Tts6jPuHTHXxnV2ETxyE22Yg/0XPT2WjqI 6RfMLu7LUCKECfL1WjDMhQNDu2UwhZZhZQcDzyFGzRKzeu2d2ZlwdVNIcQJ46/ZnanDLOZLaZJZ 8lYIacQn+Inq19SC7VROXwm59JvvYrFENkj66AeCxjPcVo32/lqZNLtlkJgLHhadcpEMIvUw31u dX+DuYn8YwhI9Rg== X-Developer-Key: i=jacopo.mondi@ideasonboard.com; a=openpgp; fpr=72392EDC88144A65C701EA9BA5826A2587AD026B X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Import the v4l2-isp.h header from the Linux kernel sources. The file has not been merged in mainline Linux yet but is available at: https://lore.kernel.org/all/20250915-extensible-parameters-validation-v5-0-e6db94468af3@ideasonboard.com/ Create the include/linux/media/ directory so that header files exported from the kernel which include this file do not need to be adjusted when imported in libcamera. Signed-off-by: Jacopo Mondi Tested-By: Antoine Bouyer --- include/linux/media/v4l2-isp.h | 100 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/include/linux/media/v4l2-isp.h b/include/linux/media/v4l2-isp.h new file mode 100644 index 0000000000000000000000000000000000000000..fed89b5678585a3565d33cf873d0313dc089524f --- /dev/null +++ b/include/linux/media/v4l2-isp.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Video4Linux2 generic ISP parameters and statistics support + * + * Copyright (C) 2025 Ideas On Board Oy + * Author: Jacopo Mondi + */ + +#ifndef _V4L2_ISP_H_ +#define _V4L2_ISP_H_ + +#include +#include + +#define V4L2_PARAMS_FL_BLOCK_DISABLE (1U << 0) +#define V4L2_PARAMS_FL_BLOCK_ENABLE (1U << 1) + +/* + * Reserve the first 8 bits for V4L2_PARAMS_FL_* flag. + * + * Driver-specific flags should be defined as: + * #define PLATFORM_SPECIFIC_FLAG0 ((1U << V4L2_PARAMS_FL_DRIVER_FLAGS(0)) + * #define PLATFORM_SPECIFIC_FLAG1 ((1U << V4L2_PARAMS_FL_DRIVER_FLAGS(1)) + */ +#define V4L2_PARAMS_FL_DRIVER_FLAGS(n) ((n) + 8) + +/** + * struct v4l2_params_block_header - V4L2 extensible parameters block header + * + * This structure represents the common part of all the ISP configuration + * blocks. Each parameters block shall embed an instance of this structure type + * as its first member, followed by the block-specific configuration data. The + * driver inspects this common header to discern the block type and its size and + * properly handle the block content. + * + * The @type field is an ISP driver-specific value that identifies the block + * type. The @size field specifies the size of the parameters block. + * + * The @flags field is a bitmask of per-block flags V4L2_PARAMS_FL_* and + * driver-specific flags specified by the driver header. + * + * @type: The parameters block type (driver-specific) + * @flags: A bitmask of block flags (driver-specific) + * @size: Size (in bytes) of the parameters block, including this header + */ +struct v4l2_params_block_header { + __u16 type; + __u16 flags; + __u32 size; +} __attribute__((aligned(8))); + +/** + * v4l2_params_buffer_size - Calculate size of v4l2_params_buffer for a platform + * + * Users of the v4l2 extensible parameters will have differing sized data arrays + * depending on their specific parameter buffers. Drivers and userspace will + * need to be able to calculate the appropriate size of the struct to + * accommodate all ISP configuration blocks provided by the platform. + * This macro provides a convenient tool for the calculation. + * + * @max_params_size: The total size of the ISP configuration blocks + */ +#define v4l2_params_buffer_size(max_params_size) \ + (offsetof(struct v4l2_params_buffer, data) + (max_params_size)) + +/** + * struct v4l2_params_buffer - V4L2 extensible parameters configuration + * + * This struct contains the configuration parameters of the ISP algorithms, + * serialized by userspace into a data buffer. Each configuration parameter + * block is represented by a block-specific structure which contains a + * :c:type:`v4l2_params_block_header` entry as first member. Userspace populates + * the @data buffer with configuration parameters for the blocks that it intends + * to configure. As a consequence, the data buffer effective size changes + * according to the number of ISP blocks that userspace intends to configure and + * is set by userspace in the @data_size field. + * + * The parameters buffer is versioned by the @version field to allow modifying + * and extending its definition. Userspace shall populate the @version field to + * inform the driver about the version it intends to use. The driver will parse + * and handle the @data buffer according to the data layout specific to the + * indicated version and return an error if the desired version is not + * supported. + * + * For each ISP block that userspace wants to configure, a block-specific + * structure is appended to the @data buffer, one after the other without gaps + * in between nor overlaps. Userspace shall populate the @data_size field with + * the effective size, in bytes, of the @data buffer. + * + * @version: The parameters buffer version (driver-specific) + * @data_size: The configuration data effective size, excluding this header + * @data: The configuration data + */ +struct v4l2_params_buffer { + __u32 version; + __u32 data_size; + __u8 data[] __counted_by(data_size); +}; + +#endif /* _V4L2_ISP_H_ */ From patchwork Fri Sep 26 14:39:34 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24474 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id CF085C328C for ; Fri, 26 Sep 2025 14:40:01 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C895D6B605; Fri, 26 Sep 2025 16:39:56 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="lAYEggcQ"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2BBCA6B5C2 for ; Fri, 26 Sep 2025 16:39:53 +0200 (CEST) Received: from [192.168.1.100] (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4C71614B0; Fri, 26 Sep 2025 16:38:27 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758897507; bh=+Fr7v0haJUdYkbqLX5PxEimUjLQcrLUSYtyDj2wqy7Y=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=lAYEggcQeyPKAkt7brZ6hn88M+GIjMymOI08g5neolQXrPkJtids7dwHI2YbQyFEH L2LHL53bm4WFIrq1PkoVxhBdE74Px83QxkmbrV6GPg6Nzu0v6xJsoFiI+q4MVKsroE M/Ccz53ZaEVlkM+pOBySZY95aNQCH//o3n3KGL6w= From: Jacopo Mondi Date: Fri, 26 Sep 2025 16:39:34 +0200 Subject: [PATCH v3 2/5] include: linux: v4l2-isp: Provide __counted_by() MIME-Version: 1.0 Message-Id: <20250926-v4l2-params-v3-2-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 X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=1458; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=+Fr7v0haJUdYkbqLX5PxEimUjLQcrLUSYtyDj2wqy7Y=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBo1qW1qa3CTWsNViLCsVNld8vbH6473BrkHRRcG miyMuF+r3GJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaNaltQAKCRByNAaPFqFW PF58EAC62o8VIS8uIsvKcl4W8ZgbAArg5ARMX9dGf3FB4fQ97qO3xijDhdHhaDc8gCdIg5woUZm 62hnPin/yGUPgpJDsyuYaTVwR18UuxYsKEUxDv2jv60juaTCjAmYQowyGBJYH9RGVqBIymAan5i F8j+bDMeBpYPOg6IAVj3Oj711F6TeL6T1GovRjijk2Yv7giUj29/QKGN9yBJrDIBoTvIuoHQJvF 4euTAjxUIBaCGLj7oMYusQhq2TeZ7h4K9VRDEZuPk3HnNChCtIFr1iu8vZQ+twkE+kquxIh9OlZ eigL4aAALvJgp7vR5tYDSeh29bOaIKtzR4zFmyPiuZS+LwJT+OZE2/922c1Qx5CSGM1nprUzsUG neYdKoVSxY0OuZhdDTteZo5Ns+x/e5NflmGoH0wHMqWNy9gMCjR36o8co0St9NIpA17SfYSSvG+ 4a/wn7lCWckFNUaodWuRGy63QxPnhUY8yvHY16hHFd9XVHgNcX0q7Nosidv2bNRsXGyTUnURYHZ H1YWHV1tbZoBoHMzAKt9EKzAGTothclFcHK0w15zg48geYEmXqPQBSgg2BDbSHv6BIAB1d5Nmlc PpMYxRWUknH3qlR/vRi8Y4UKdK8CV/mxwx1zJ6yNw3eItWGoEkblY7zPB+KUXDUD1BIx7qZznFx KCDF83ElwcDn3xQ== X-Developer-Key: i=jacopo.mondi@ideasonboard.com; a=openpgp; fpr=72392EDC88144A65C701EA9BA5826A2587AD026B X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The v4l2-isp.h header exported from version https://lore.kernel.org/all/20250915-extensible-parameters-validation-v5-0-e6db94468af3@ideasonboard.com/ includes the __counted_by() macro, which is not availale in Linux uAPI headers older than version v6.5. Provide the macro here, to support older kernel versions. Signed-off-by: Jacopo Mondi --- include/linux/media/v4l2-isp.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/linux/media/v4l2-isp.h b/include/linux/media/v4l2-isp.h index fed89b5678585a3565d33cf873d0313dc089524f..ea23dfdeeab9e69959cd8fa3c4853e931f36198a 100644 --- a/include/linux/media/v4l2-isp.h +++ b/include/linux/media/v4l2-isp.h @@ -12,6 +12,24 @@ #include #include +/* + * Provide __counted_by() if not available in linux/stddef.h + * + * The Linux macro __counted_by() has been introduced in kernel v6.5 and + * is not available in older kernel version. + * + * See commit dd06e72e68bc ("Compiler Attributes: Add __counted_by macro") + * + * Provide it here if not available. + */ +#if not defined(__counted_by) +#if __has_attribute(__counted_by__) +# define __counted_by(member) __attribute__((__counted_by__(member))) +#else +# define __counted_by(member) +#endif +#endif + #define V4L2_PARAMS_FL_BLOCK_DISABLE (1U << 0) #define V4L2_PARAMS_FL_BLOCK_ENABLE (1U << 1) From patchwork Fri Sep 26 14:39:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24475 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 22A2DC328C for ; Fri, 26 Sep 2025 14:40:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D0DDD6B611; Fri, 26 Sep 2025 16:39:57 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="fgZ547+8"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EC8BD6B5C2 for ; Fri, 26 Sep 2025 16:39:54 +0200 (CEST) Received: from [192.168.1.100] (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 347161807; Fri, 26 Sep 2025 16:38:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758897509; bh=gXc5sZbBgvAbTOKozpjjDwEs1SvbtoYTim0B6XcQ4I4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=fgZ547+8Ododu6K0vzeKBpKvyRLzwm2yYmIsKiPUb6ikJmEDRrxp4hh8avg9CS6s8 J6THtKiv1Uez9KCVr7VZXLHczdhjiGWiLkb2AxpjYi1LfaB28Qx8KbhjJtbYEUT38f jk6HZnalZYq+54DKMVUQZ1x45jR16vfwGUpJe1BE= From: Jacopo Mondi Date: Fri, 26 Sep 2025 16:39:35 +0200 Subject: [PATCH v3 3/5] ipa: Update Mali C55 header file and adjust IPA MIME-Version: 1.0 Message-Id: <20250926-v4l2-params-v3-3-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 , Antoine Bouyer X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=26183; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=gXc5sZbBgvAbTOKozpjjDwEs1SvbtoYTim0B6XcQ4I4=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBo1qW1AS9pY4lzIlr1ZKaSyTmpmzufx9wpnofBq YAAR8uU+q+JAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaNaltQAKCRByNAaPFqFW PAcjEADBw/UA0qQEBXyxTZ5h7q4tAoMw7TYShmTWQYi5UoCIIR5odvfKp86Rd5USTxBAsmLT8iS 8jDwWSuEqdk5r5ZhS8vWUO1wpoulGKTy8VhJBZmYYJ7yoINkpX0uJGtVxM2Hp3s+U6F3ntrSYbX nWlBQsHxYCjrAru5xwH1UwROQMqQ1HAm2/cQ3AQky5qKkuD6uReom5DRHygbflptmtkF+yrh7p3 GN4Fz21cj1gN/kHD6xbMttl53s4EDOWs1u6hdx5DnakRcstTsJs98DHWCutUjvLKlT6wKe1kjhJ J9cItfQy8OOvrP11mVgF0AKzI57YlUw1FAYSQ+l85GU5nfX0/kavHpYfWPTvYfYdak0JK8qZlfQ D6t2eXtM0tYbbaFmKBBwGQhQUKSjVOvgDtp4IYhvDnerkCX2E4RBI0aELGFQOGS8qgTSD2BqUjp hfX3FX9W3EwJD52l4rx9AjxXwoK7kK9eWefWOkv03Nj5TusoEccFNEeXmqUbtI5Y2zaW8HgsBPH A9E1OdPH4kKaStGnVYpI8wEAa20HrFenPIwPiczu4fMrz52AV4mYhEf9ONwnB8dcPKvoWRSrFbM XGH2cpAmvANy7X/EFLXVmLllqYuxONnDuYvuyvNyk84pGUaRrPxskQtoUI7k6eqnbfGhDdnTKDF n0amG2ycrRa2AXg== X-Developer-Key: i=jacopo.mondi@ideasonboard.com; a=openpgp; fpr=72392EDC88144A65C701EA9BA5826A2587AD026B X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Update Mali C55 header file with the v11 version of the patch series, based on v4l2 extensible parameters, sent to the linux-media mailing list at: https://lore.kernel.org/all/20250714-c55-v11-0-bc20e460e42a@ideasonboard.com/ Adjust the IPA module to use the new v4l2-isp.h header file. Signed-off-by: Jacopo Mondi Tested-By: Antoine Bouyer --- include/linux/mali-c55-config.h | 162 +++++--------------------------- src/ipa/mali-c55/algorithms/agc.cpp | 28 +++--- src/ipa/mali-c55/algorithms/agc.h | 2 +- src/ipa/mali-c55/algorithms/algorithm.h | 2 +- src/ipa/mali-c55/algorithms/awb.cpp | 14 +-- src/ipa/mali-c55/algorithms/awb.h | 2 +- src/ipa/mali-c55/algorithms/blc.cpp | 8 +- src/ipa/mali-c55/algorithms/blc.h | 2 +- src/ipa/mali-c55/algorithms/lsc.cpp | 14 +-- src/ipa/mali-c55/algorithms/lsc.h | 2 +- src/ipa/mali-c55/mali-c55.cpp | 10 +- src/ipa/mali-c55/module.h | 2 +- 12 files changed, 67 insertions(+), 181 deletions(-) diff --git a/include/linux/mali-c55-config.h b/include/linux/mali-c55-config.h index b31415597e886496b65f8fb396c095618467f1ac..3e22a9e50dce85b69fc96f8e6cd03d199430eb8b 100644 --- a/include/linux/mali-c55-config.h +++ b/include/linux/mali-c55-config.h @@ -9,6 +9,22 @@ #define __UAPI_MALI_C55_CONFIG_H #include +#include + +#include + +#define V4L2_CID_MALI_C55_CAPABILITIES (V4L2_CID_USER_MALI_C55_BASE + 0x0) +#define MALI_C55_GPS_PONG (1U << 0) +#define MALI_C55_GPS_WDR (1U << 1) +#define MALI_C55_GPS_COMPRESSION (1U << 2) +#define MALI_C55_GPS_TEMPER (1U << 3) +#define MALI_C55_GPS_SINTER_LITE (1U << 4) +#define MALI_C55_GPS_SINTER (1U << 5) +#define MALI_C55_GPS_IRIDIX_LTM (1U << 6) +#define MALI_C55_GPS_IRIDIX_GTM (1U << 7) +#define MALI_C55_GPS_CNR (1U << 8) +#define MALI_C55_GPS_FRSCALER (1U << 9) +#define MALI_C55_GPS_DS_PIPE (1U << 10) /* * Frames are split into zones of almost equal width and height - a zone is a @@ -228,65 +244,6 @@ enum mali_c55_param_block_type { MALI_C55_PARAM_MESH_SHADING_SELECTION, }; -#define MALI_C55_PARAM_BLOCK_FL_NONE 0 -#define MALI_C55_PARAM_BLOCK_FL_DISABLED BIT(0) - -/** - * struct mali_c55_params_block_header - Mali-C55 parameter block header - * - * This structure represents the common part of all the ISP configuration - * blocks. Each parameters block embeds an instance of this structure type - * as its first member, followed by the block-specific configuration data. The - * driver inspects this common header to discern the block type and its size and - * properly handle the block content by casting it to the correct block-specific - * type. - * - * The @type field is one of the values enumerated by - * :c:type:`mali_c55_param_block_type` and specifies how the data should be - * interpreted by the driver. The @size field specifies the size of the - * parameters block and is used by the driver for validation purposes. The - * @flags field holds a bitmask of per-block flags MALI_C55_PARAM_BLOCK_FL_*. - * - * If userspace wants to disable an ISP block the - * MALI_C55_PARAM_BLOCK_FL_DISABLED bit should be set in the @flags field. In - * that case userspace may optionally omit the remainder of the configuration - * block, which will in any case be ignored by the driver. If a new - * configuration of an ISP block has to be applied userspace shall fully - * populate the ISP block and omit setting the MALI_C55_PARAM_BLOCK_FL_DISABLED - * bit in the @flags field. - * - * Userspace is responsible for correctly populating the parameters block header - * fields (@type, @flags and @size) and correctly populate the block-specific - * parameters. - * - * For example: - * - * .. code-block:: c - * - * void populate_sensor_offs(struct mali_c55_params_block_header *block) { - * block->type = MALI_C55_PARAM_BLOCK_SENSOR_OFFS; - * block->enabled = MALI_C55_PARAM_BLOCK_FL_NONE; - * block->size = sizeof(struct mali_c55_params_sensor_off_preshading); - * - * struct mali_c55_params_sensor_off_preshading *sensor_offs = - * (struct mali_c55_params_sensor_off_preshading *)block; - * - * sensor_offs->chan00 = offset00; - * sensor_offs->chan01 = offset01; - * sensor_offs->chan10 = offset10; - * sensor_offs->chan11 = offset11; - * } - * - * @type: The parameters block type from :c:type:`mali_c55_param_block_type` - * @flags: Bitmask of block flags - * @size: Size (in bytes) of the parameters block - */ -struct mali_c55_params_block_header { - __u16 type; - __u16 flags; - __u32 size; -} __attribute__((aligned(8))); - /** * struct mali_c55_params_sensor_off_preshading - offset subtraction for each * color channel @@ -305,7 +262,7 @@ struct mali_c55_params_block_header { * @chan11: Offset for color channel 11 (default: B) */ struct mali_c55_params_sensor_off_preshading { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u32 chan00; __u32 chan01; __u32 chan10; @@ -470,7 +427,7 @@ enum mali_c55_aexp_hist_plane_mode { * This parameter is unused for the post-Iridix Histogram */ struct mali_c55_params_aexp_hist { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u8 skip_x; __u8 offset_x; __u8 skip_y; @@ -502,7 +459,7 @@ struct mali_c55_params_aexp_hist { * @nodes_used_horiz */ struct mali_c55_params_aexp_weights { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u8 nodes_used_horiz; __u8 nodes_used_vert; __u8 zone_weights[MALI_C55_MAX_ZONES]; @@ -520,7 +477,7 @@ struct mali_c55_params_aexp_weights { * @gain: The digital gain value to apply, in Q5.8 format. */ struct mali_c55_params_digital_gain { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u16 gain; }; @@ -560,7 +517,7 @@ enum mali_c55_awb_stats_mode { * @gain11: Multiplier for colour channel 11 */ struct mali_c55_params_awb_gains { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u16 gain00; __u16 gain01; __u16 gain10; @@ -635,7 +592,7 @@ enum mali_c55_params_awb_tap_points { * @cb_low: B/G ratio trim low (Q4.8 format) */ struct mali_c55_params_awb_config { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u8 tap_point; __u8 stats_mode; __u16 white_level; @@ -745,7 +702,7 @@ struct mali_c55_params_awb_config { * @mesh: Mesh shading correction tables */ struct mali_c55_params_mesh_shading_config { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u8 mesh_show; __u8 mesh_scale; __u8 mesh_page_r; @@ -800,7 +757,7 @@ enum mali_c55_params_mesh_alpha_bank { * @mesh_strength: Mesh strength in Q4.12 format [0..4096] */ struct mali_c55_params_mesh_shading_selection { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u8 mesh_alpha_bank_r; __u8 mesh_alpha_bank_g; __u8 mesh_alpha_bank_b; @@ -835,75 +792,4 @@ struct mali_c55_params_mesh_shading_selection { sizeof(struct mali_c55_params_mesh_shading_config) + \ sizeof(struct mali_c55_params_mesh_shading_selection)) -/** - * struct mali_c55_params_buffer - 3A configuration parameters - * - * This struct contains the configuration parameters of the Mali-C55 ISP - * algorithms, serialized by userspace into a data buffer. Each configuration - * parameter block is represented by a block-specific structure which contains a - * :c:type:`mali_c55_params_block_header` entry as first member. Userspace - * populates the @data buffer with configuration parameters for the blocks that - * it intends to configure. As a consequence, the data buffer effective size - * changes according to the number of ISP blocks that userspace intends to - * configure. - * - * The parameters buffer is versioned by the @version field to allow modifying - * and extending its definition. Userspace shall populate the @version field to - * inform the driver about the version it intends to use. The driver will parse - * and handle the @data buffer according to the data layout specific to the - * indicated version and return an error if the desired version is not - * supported. - * - * For each ISP block that userspace wants to configure, a block-specific - * structure is appended to the @data buffer, one after the other without gaps - * in between nor overlaps. Userspace shall populate the @total_size field with - * the effective size, in bytes, of the @data buffer. - * - * The expected memory layout of the parameters buffer is:: - * - * +-------------------- struct mali_c55_params_buffer ------------------+ - * | version = MALI_C55_PARAM_BUFFER_V1; | - * | total_size = sizeof(struct mali_c55_params_sensor_off_preshading) | - * | sizeof(struct mali_c55_params_aexp_hist); | - * | +------------------------- data ---------------------------------+ | - * | | +--------- struct mali_c55_params_sensor_off_preshading ------+ | | - * | | | +-------- struct mali_c55_params_block_header header -----+ | | | - * | | | | type = MALI_C55_PARAM_BLOCK_SENSOR_OFFS; | | | | - * | | | | flags = MALI_C55_PARAM_BLOCK_FL_NONE; | | | | - * | | | | size = | | | | - * | | | | sizeof(struct mali_c55_params_sensor_off_preshading);| | | | - * | | | +---------------------------------------------------------+ | | | - * | | | chan00 = ...; | | | - * | | | chan01 = ...; | | | - * | | | chan10 = ...; | | | - * | | | chan11 = ...; | | | - * | | +------------ struct mali_c55_params_aexp_hist ---------------+ | | - * | | | +-------- struct mali_c55_params_block_header header -----+ | | | - * | | | | type = MALI_C55_PARAM_BLOCK_AEXP_HIST; | | | | - * | | | | flags = MALI_C55_PARAM_BLOCK_FL_NONE; | | | | - * | | | | size = sizeof(struct mali_c55_params_aexp_hist); | | | | - * | | | +---------------------------------------------------------+ | | | - * | | | skip_x = ...; | | | - * | | | offset_x = ...; | | | - * | | | skip_y = ...; | | | - * | | | offset_y = ...; | | | - * | | | scale_bottom = ...; | | | - * | | | scale_top = ...; | | | - * | | | plane_mode = ...; | | | - * | | | tap_point = ...; | | | - * | | +-------------------------------------------------------------+ | | - * | +-----------------------------------------------------------------+ | - * +---------------------------------------------------------------------+ - * - * @version: The version from :c:type:`mali_c55_param_buffer_version` - * @total_size: The Mali-C55 configuration data effective size, excluding this - * header - * @data: The Mali-C55 configuration blocks data - */ -struct mali_c55_params_buffer { - __u8 version; - __u32 total_size; - __u8 data[MALI_C55_PARAMS_MAX_SIZE]; -}; - #endif /* __UAPI_MALI_C55_CONFIG_H */ diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp index f60fddac3f04fd6f09dc782e929ff1593758c29b..da47cf15be49327a592e850817f2863ab62cb404 100644 --- a/src/ipa/mali-c55/algorithms/agc.cpp +++ b/src/ipa/mali-c55/algorithms/agc.cpp @@ -253,7 +253,7 @@ size_t Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContex gain = activeState.agc.manual.ispGain; block.header->type = MALI_C55_PARAM_BLOCK_DIGITAL_GAIN; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(struct mali_c55_params_digital_gain); block.digital_gain->gain = floatingToFixedPoint<5, 8, uint16_t, double>(gain); @@ -266,7 +266,7 @@ size_t Agc::fillParamsBuffer(mali_c55_params_block block, enum mali_c55_param_block_type type) { block.header->type = type; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(struct mali_c55_params_aexp_hist); /* Collect every 3rd pixel horizontally */ @@ -292,7 +292,7 @@ size_t Agc::fillWeightsArrayBuffer(mali_c55_params_block block, enum mali_c55_param_block_type type) { block.header->type = type; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(struct mali_c55_params_aexp_weights); /* We use every zone - a 15x15 grid */ @@ -314,30 +314,30 @@ size_t Agc::fillWeightsArrayBuffer(mali_c55_params_block block, } void Agc::prepare(IPAContext &context, const uint32_t frame, - IPAFrameContext &frameContext, mali_c55_params_buffer *params) + IPAFrameContext &frameContext, v4l2_params_buffer *params) { mali_c55_params_block block; - block.data = ¶ms->data[params->total_size]; - params->total_size += fillGainParamBlock(context, frameContext, block); + block.data = ¶ms->data[params->data_size]; + params->data_size += fillGainParamBlock(context, frameContext, block); if (frame > 0) return; - block.data = ¶ms->data[params->total_size]; - params->total_size += fillParamsBuffer(block, + block.data = ¶ms->data[params->data_size]; + params->data_size += fillParamsBuffer(block, MALI_C55_PARAM_BLOCK_AEXP_HIST); - block.data = ¶ms->data[params->total_size]; - params->total_size += fillWeightsArrayBuffer(block, + block.data = ¶ms->data[params->data_size]; + params->data_size += fillWeightsArrayBuffer(block, MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS); - block.data = ¶ms->data[params->total_size]; - params->total_size += fillParamsBuffer(block, + block.data = ¶ms->data[params->data_size]; + params->data_size += fillParamsBuffer(block, MALI_C55_PARAM_BLOCK_AEXP_IHIST); - block.data = ¶ms->data[params->total_size]; - params->total_size += fillWeightsArrayBuffer(block, + block.data = ¶ms->data[params->data_size]; + params->data_size += fillWeightsArrayBuffer(block, MALI_C55_PARAM_BLOCK_AEXP_IHIST_WEIGHTS); } diff --git a/src/ipa/mali-c55/algorithms/agc.h b/src/ipa/mali-c55/algorithms/agc.h index 0b4bf7eda1c2a7c9894f6932452fea5f53699b30..64caf99350c1d1835832311a94a88a2bfde5721c 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, - mali_c55_params_buffer *params) override; + v4l2_params_buffer *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/algorithm.h b/src/ipa/mali-c55/algorithms/algorithm.h index ec8dd3973eaf2d804d8de8620840f716340e9cfd..c28789f6a619cf7fc05ffb705098ed8d1fac93b8 100644 --- a/src/ipa/mali-c55/algorithms/algorithm.h +++ b/src/ipa/mali-c55/algorithms/algorithm.h @@ -22,7 +22,7 @@ class Algorithm : public libcamera::ipa::Algorithm }; union mali_c55_params_block { - struct mali_c55_params_block_header *header; + struct v4l2_params_block_header *header; struct mali_c55_params_sensor_off_preshading *sensor_offs; struct mali_c55_params_aexp_hist *aexp_hist; struct mali_c55_params_aexp_weights *aexp_weights; diff --git a/src/ipa/mali-c55/algorithms/awb.cpp b/src/ipa/mali-c55/algorithms/awb.cpp index 3d546e5a854b8aa02987c44f57109a6171e3794b..6b2cbed9de1ebfe9a2466ebe999eceac44fe5deb 100644 --- a/src/ipa/mali-c55/algorithms/awb.cpp +++ b/src/ipa/mali-c55/algorithms/awb.cpp @@ -47,7 +47,7 @@ size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context IPAFrameContext &frameContext) { block.header->type = MALI_C55_PARAM_BLOCK_AWB_GAINS; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(struct mali_c55_params_awb_gains); double rGain = context.activeState.awb.rGain; @@ -77,7 +77,7 @@ size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context size_t Awb::fillConfigParamBlock(mali_c55_params_block block) { block.header->type = MALI_C55_PARAM_BLOCK_AWB_CONFIG; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(struct mali_c55_params_awb_config); /* Tap the stats after the purple fringe block */ @@ -126,18 +126,18 @@ size_t Awb::fillConfigParamBlock(mali_c55_params_block block) } void Awb::prepare(IPAContext &context, const uint32_t frame, - IPAFrameContext &frameContext, mali_c55_params_buffer *params) + IPAFrameContext &frameContext, v4l2_params_buffer *params) { mali_c55_params_block block; - block.data = ¶ms->data[params->total_size]; + block.data = ¶ms->data[params->data_size]; - params->total_size += fillGainsParamBlock(block, context, frameContext); + params->data_size += fillGainsParamBlock(block, context, frameContext); if (frame > 0) return; - block.data = ¶ms->data[params->total_size]; - params->total_size += fillConfigParamBlock(block); + block.data = ¶ms->data[params->data_size]; + params->data_size += fillConfigParamBlock(block); } 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 2351d405553058dbff569e9e09e265a56baaa23f..b5ff121041d1a01e3a51d64b87a90fb2e1d8dd10 100644 --- a/src/ipa/mali-c55/algorithms/awb.h +++ b/src/ipa/mali-c55/algorithms/awb.h @@ -22,7 +22,7 @@ public: const IPACameraSensorInfo &configInfo) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, - mali_c55_params_buffer *params) override; + v4l2_params_buffer *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/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp index 2a54c86a91f83d24183cb7236fcd5181302eb622..8fd0f10c3082030a36a256830042d733ed4c8c78 100644 --- a/src/ipa/mali-c55/algorithms/blc.cpp +++ b/src/ipa/mali-c55/algorithms/blc.cpp @@ -85,10 +85,10 @@ int BlackLevelCorrection::configure(IPAContext &context, void BlackLevelCorrection::prepare([[maybe_unused]] IPAContext &context, const uint32_t frame, [[maybe_unused]] IPAFrameContext &frameContext, - mali_c55_params_buffer *params) + v4l2_params_buffer *params) { mali_c55_params_block block; - block.data = ¶ms->data[params->total_size]; + block.data = ¶ms->data[params->data_size]; if (frame > 0) return; @@ -97,7 +97,7 @@ void BlackLevelCorrection::prepare([[maybe_unused]] IPAContext &context, return; block.header->type = MALI_C55_PARAM_BLOCK_SENSOR_OFFS; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(mali_c55_params_sensor_off_preshading); block.sensor_offs->chan00 = offset00; @@ -105,7 +105,7 @@ void BlackLevelCorrection::prepare([[maybe_unused]] IPAContext &context, block.sensor_offs->chan10 = offset10; block.sensor_offs->chan11 = offset11; - params->total_size += block.header->size; + params->data_size += block.header->size; } 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 9696e8e9f2aa8b9076a3a41fb8f5ea356e32be12..cf10505ce2908df0d5e658d3fdce663729c7ea76 100644 --- a/src/ipa/mali-c55/algorithms/blc.h +++ b/src/ipa/mali-c55/algorithms/blc.h @@ -22,7 +22,7 @@ public: const IPACameraSensorInfo &configInfo) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, - mali_c55_params_buffer *params) override; + v4l2_params_buffer *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 c43d034a181edb7559706189f8d75edd67a2dc08..35f1d876e60db252a45cadb771e541735749d106 100644 --- a/src/ipa/mali-c55/algorithms/lsc.cpp +++ b/src/ipa/mali-c55/algorithms/lsc.cpp @@ -111,7 +111,7 @@ int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData size_t Lsc::fillConfigParamsBlock(mali_c55_params_block block) const { block.header->type = MALI_C55_PARAM_MESH_SHADING_CONFIG; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(struct mali_c55_params_mesh_shading_config); block.shading_config->mesh_show = false; @@ -131,7 +131,7 @@ size_t Lsc::fillSelectionParamsBlock(mali_c55_params_block block, uint8_t bank, uint8_t alpha) const { block.header->type = MALI_C55_PARAM_MESH_SHADING_SELECTION; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(struct mali_c55_params_mesh_shading_selection); block.shading_selection->mesh_alpha_bank_r = bank; @@ -170,7 +170,7 @@ std::tuple Lsc::findBankAndAlpha(uint32_t ct) const void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, [[maybe_unused]] IPAFrameContext &frameContext, - mali_c55_params_buffer *params) + v4l2_params_buffer *params) { /* * For each frame we assess the colour temperature of the **last** frame @@ -194,9 +194,9 @@ void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, } mali_c55_params_block block; - block.data = ¶ms->data[params->total_size]; + block.data = ¶ms->data[params->data_size]; - params->total_size += fillSelectionParamsBlock(block, bank, alpha); + params->data_size += fillSelectionParamsBlock(block, bank, alpha); if (frame > 0) return; @@ -205,8 +205,8 @@ 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 = ¶ms->data[params->total_size]; - params->total_size += fillConfigParamsBlock(block); + block.data = ¶ms->data[params->data_size]; + params->data_size += fillConfigParamsBlock(block); } REGISTER_IPA_ALGORITHM(Lsc, "Lsc") diff --git a/src/ipa/mali-c55/algorithms/lsc.h b/src/ipa/mali-c55/algorithms/lsc.h index d11e23bc7c34fa3e1f45ccf015b50f3d390d7159..9019a61aa547e41154615eba88547d3eee1634e2 100644 --- a/src/ipa/mali-c55/algorithms/lsc.h +++ b/src/ipa/mali-c55/algorithms/lsc.h @@ -23,7 +23,7 @@ public: int init(IPAContext &context, const YamlObject &tuningData) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, - mali_c55_params_buffer *params) override; + v4l2_params_buffer *params) override; private: static constexpr unsigned int kRedOffset = 0; static constexpr unsigned int kGreenOffset = 1024; diff --git a/src/ipa/mali-c55/mali-c55.cpp b/src/ipa/mali-c55/mali-c55.cpp index 7d45e7310aecdae0e47655e6d2e8830e776d74cd..a6d3e984a438c01509ed27469d9f20c25bc884cf 100644 --- a/src/ipa/mali-c55/mali-c55.cpp +++ b/src/ipa/mali-c55/mali-c55.cpp @@ -331,22 +331,22 @@ void IPAMaliC55::queueRequest(const uint32_t request, const ControlList &control void IPAMaliC55::fillParams(unsigned int request, [[maybe_unused]] uint32_t bufferId) { - struct mali_c55_params_buffer *params; + struct v4l2_params_buffer *params; IPAFrameContext &frameContext = context_.frameContexts.get(request); - params = reinterpret_cast( + params = reinterpret_cast( buffers_.at(bufferId).planes()[0].data()); - memset(params, 0, sizeof(mali_c55_params_buffer)); + 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->total_size <= MALI_C55_PARAMS_MAX_SIZE); + ASSERT(params->data_size <= MALI_C55_PARAMS_MAX_SIZE); } - size_t bytesused = offsetof(struct mali_c55_params_buffer, data) + params->total_size; + size_t bytesused = offsetof(struct v4l2_params_buffer, data) + params->data_size; paramsComputed.emit(request, bytesused); } diff --git a/src/ipa/mali-c55/module.h b/src/ipa/mali-c55/module.h index 4f6a4f18bfaf83263ccb5b7eb1723da9b655cc3c..434d2c585d2f4eb03402c57e87302fc82e82a0f0 100644 --- a/src/ipa/mali-c55/module.h +++ b/src/ipa/mali-c55/module.h @@ -20,7 +20,7 @@ namespace libcamera { namespace ipa::mali_c55 { using Module = ipa::Module; + v4l2_params_buffer, mali_c55_stats_buffer>; } /* namespace ipa::mali_c55 */ From patchwork Fri Sep 26 14:39:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24476 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id A50B2C328C for ; Fri, 26 Sep 2025 14:40:05 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9A7A16B60E; Fri, 26 Sep 2025 16:40:01 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="AU/SdOtN"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5618A6B60E for ; Fri, 26 Sep 2025 16:39:57 +0200 (CEST) Received: from [192.168.1.100] (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2FAE914B0; Fri, 26 Sep 2025 16:38:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758897510; bh=7Ee0rX17/WUpoPHK1wgIT+gfWlEw7zHRDHPoo9rNdi8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=AU/SdOtNoUHWqcfrDIGiqo0Z+3vJRaAt0/6Zzx+kQlCeltFfhSsxwUIe2+yoY8Oj6 D3O7B73aP8DGREbH38pG5dGqVKkEyxRLXEDUd+Fpp3nhp3yKqA66VrRg4QsTvCSAK6 YTEycJgiaP2wBx0w+QcAcEO6Tn5um18U8yPG5YCo= From: Jacopo Mondi Date: Fri, 26 Sep 2025 16:39:36 +0200 Subject: [PATCH v3 4/5] ipa: libipa: Introduce V4L2Params MIME-Version: 1.0 Message-Id: <20250926-v4l2-params-v3-4-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 , Antoine Bouyer X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=25777; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=7Ee0rX17/WUpoPHK1wgIT+gfWlEw7zHRDHPoo9rNdi8=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBo1qW29QcGyykjFYS9qNnDk7OpmYYHO0/iHQ9Vw +G9whR9KW2JAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaNaltgAKCRByNAaPFqFW PPwiD/9gzZq6DW8gcGF4wYuYLhSBnjAzD9D2aS2pz5Cl42oI6qrHJc69NEBYvJDXsFh1mrQspcG kHo0f9nUIjXO8AWD/jvzZh7HbLerjsQtUzXaWDPOpEJLQUi7XZMu2t5OqdvDinjYY0lbXQ/rsTn zIqnUroM0yCKV2LHZXeZKC4nf1Z4KpVkQwcpiugRpFuPm+NDnAjjtqDmQqp55KgW9V5zo6g4jta C1//T3FWUXCjS//Rxsk/UDacU9wQrU6LNbcGlHJzcRhb/MrOTY1xUGVeufYVpUQwdIEP5MtJ6ku InLu333BSQ+l3tAP49HawIiKR/my4WYX3ekNgePvmqI+4qgaqN8wLa8VbJKbN4LouHFmw/+IKu3 m42jLuyQZqh5DbkYjnsDnk8wFqhWoC0/J07PRUOI4FU5aJKt7Go139+UFsC0Krr98UJQmAUzJ8k 782nQEugNdKDfzmNYlFSjUqSskW5p6cXvA3pF3/KGhLx4ExcDsS1o52B2YzgU0QUFVRjn/NTVv8 DkYDjGKWupwYtUNjQkrOh/tnnViQgnPuLNLtHMbDxjmb28rhBOzEJuoDECH2fBPzYEKa8SHKfnV jV8qDCVQNnmM6nVEdAuLefF/vRfXzH6uYNAEZmmEv7b5dT7onTUeA5Nku8xHHlvk787cJt9EiQk 8tIgvW7iCAtXe6g== X-Developer-Key: i=jacopo.mondi@ideasonboard.com; a=openpgp; fpr=72392EDC88144A65C701EA9BA5826A2587AD026B X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The existing RkISP1Params helper classes allows the RkISP1 to handle V4L2 extensible parameters format and the legacy RkIPS1-specific fixed-size parameters format. With the introduction of v4l2-isp.h in the Linux kernel the part of the RkISP1Params helper class that handles extensible parameters can be generalized so that other IPA modules can use the same helpers to populate a v4l2-params compatible buffer. Generalize the RkISP1Params class to a new libipa component named V4L2Params and derive the existing RkISP1Params from it, leaving in the RkISP1-specific implementation the handling of the legacy format. Deriving RkISP1Params from V4L2Params requires changing the size associated to each block to include the size of v4l2_params_block_header in the ipa:rkisp1::kBlockTypeInfo map as the V4L2Params::block() implementation doesn't account for that as RkIS1Params::block() implementation did. Signed-off-by: Jacopo Mondi Tested-By: Antoine Bouyer --- src/ipa/libipa/meson.build | 2 + src/ipa/libipa/v4l2_params.cpp | 262 +++++++++++++++++++++++++++++++++++++++++ src/ipa/libipa/v4l2_params.h | 142 ++++++++++++++++++++++ src/ipa/rkisp1/params.cpp | 93 +-------------- src/ipa/rkisp1/params.h | 175 +++++++++++++++------------ 5 files changed, 509 insertions(+), 165 deletions(-) diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build index 660be94054fa98b714b6bc586039081e45a6b4bc..4010739e710eb38aa6108eb8258c574a616bf3c0 100644 --- a/src/ipa/libipa/meson.build +++ b/src/ipa/libipa/meson.build @@ -16,6 +16,7 @@ libipa_headers = files([ 'lsc_polynomial.h', 'lux.h', 'module.h', + 'v4l2_params.h', 'pwl.h', ]) @@ -35,6 +36,7 @@ libipa_sources = files([ 'lsc_polynomial.cpp', 'lux.cpp', 'module.cpp', + 'v4l2_params.cpp', 'pwl.cpp', ]) diff --git a/src/ipa/libipa/v4l2_params.cpp b/src/ipa/libipa/v4l2_params.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b116d0a2f79da8ab9cf695195b317f4038202262 --- /dev/null +++ b/src/ipa/libipa/v4l2_params.cpp @@ -0,0 +1,262 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Ideas On Board + * + * V4L2 Parameters + */ + +#include "v4l2_params.h" + +namespace libcamera { + +namespace ipa { + +/** + * \file v4l2_params.cpp + * \brief Helper class to populate an ISP configuration buffer compatible with + * the generic V4L2 ISP extensible format + * + * The Linux kernel defines a generic buffer format for configuring ISP devices + * through a set of parameters in the form of V4L2 extensible parameters. The + * V4L2 extensible parameters define a serialization format for ISP parameters + * that allows userspace to populate a buffer of configuration data by appending + * them one after the other in a binary buffer. + * + * Each ISP driver compatible with the v4l2-isp format will define its own + * meta-output format identifier and defines the types of the configuration data + * of each ISP block that usually match the registers layout. + * + * The V4L2Params class represent the V4L2 extensible parameters buffer and + * allows users to populate the ISP configuration blocks, represented by the + * V4L2ParamBlock class instances. + * + * IPA implementations using this helpers should define an enumeration of ISP + * blocks the IPA module supports and use a set of common abstraction to help + * their derived implementation of V4L2Params translate the enumerated ISP block + * identifier to the actual type of the configuration data as defined by the + * kernel interface. + * + * As an example of this see the RkISP1 and Mali-C55 implementations. + */ + +/** + * \class V4L2ParamsBlock + * \brief Helper class that represents a ISP configuration block + * + * Each ISP function is associated with a set of configuration parameters + * defined by the kernel interface. + * + * This class represents an ISP block configuration entry. It is constructed + * with a reference to the memory area where the block configuration will be + * stored in the parameters buffer. The template parameter represents + * the underlying kernel-defined ISP block configuration type and allow its + * user to easily cast it to said type to populate and read the configuration + * parameters. + * + * \sa V4L2Params::block() + */ + +/** + * \fn V4L2ParamsBlock::V4L2ParamsBlock() + * \brief Construct a V4L2ParamsBlock with memory represented by \a data + * \param[in] data A view on the memory area where the ISP block is located + */ + +/** + * \fn V4L2ParamsBlock::setEnabled() + * \brief Enable/disable an ISP configuration block + * \param[in] enabled The enable flag + */ + +/** + * \fn V4L2ParamsBlock::operator->() + * \brief Access the ISP configuration block casting it to the kernel-defined + * ISP configuration type + * + * The V4L2ParamsBlock is templated with the kernel defined ISP configuration + * block type. This function allows users to easily cast a V4L2ParamsBlock to + * the underlying kernel-defined type in order to easily populate or read + * the ISP configuration data. + * + * \code{.cpp} + * + * // The kernel header defines the ISP configuration types, in example + * // struct my_isp_awb_config_data { + * // u16 gain_ch00; + * // u16 gain_ch01; + * // u16 gain_ch10; + * // u16 gain_ch11; + * // + * // } + * + * template<> V4L2ParamsBlock awbBlock + * + * awbBlock->gain_ch00 = ...; + * awbBlock->gain_ch01 = ...; + * awbBlock->gain_ch10 = ...; + * awbBlock->gain_ch11 = ...; + * + * \endcode + * + * Users of this class are not expected to create a V4L2ParamsBlock manually but + * should rather use V4L2Params::block() to retrieve a reference to the memory + * area used to construct a V4L2ParamsBlock in their overloaded + * implementation of V4L2Params::block(). + */ + +/** + * \fn V4L2ParamsBlock::operator->() const + * \copydoc V4L2ParamsBlock::operator->() + */ + +/** + * \fn V4L2ParamsBlock::operator*() const + * \copydoc V4L2ParamsBlock::operator->() + */ + +/** + * \fn V4L2ParamsBlock::operator*() + * \copydoc V4L2ParamsBlock::operator->() + */ + +/** + * \var V4L2ParamsBlock::data_ + * \brief Memory area reserved for the ISP configuration block + */ + + /** + * \class V4L2Params + * \brief Helper class that represent an ISP configuration buffer + * + * ISP implementation compatible with v4l2-isp define their ISP configuration + * buffer types compatible with the struct v4l2_params_buffer type. + * + * This class represents an ISP configuration buffer. It is constructed + * with a reference to the memory mapped buffer that will be queued to the ISP. + * + * This class is templated with the type of the enumeration of ISP blocks that + * each IPA module is expected to support. IPA modules are expected to derive + * this class by providing a 'param_traits' type the helps the class associate + * a block type with the actual memory area that represents the ISP + * configuration block. + * + * \code{.cpp} + * + * // Define the supported ISP blocks + * enum class myISPBlocks { + * Agc, + * Awb, + * ... + * }; + * + * // Associated to the ISP blocks the kernel types + * template + * struct block_type { + * }; + * + * template<> + * struct block_type { + * using type = struct my_isp_kernel_config_type_agc; + * static constextpr struct my_isp_kernel_block_type MY_ISP_TYPE_AGC; + * }; + * + * template<> + * struct block_type { + * using type = struct my_isp_kernel_config_type_awb; + * static constextpr struct my_isp_kernel_block_type MY_ISP_TYPE_AWB; + * }; + * + * + * // Convenience type to associated a block id to the 'block_type' overload + * struct params_traits { + * using id_type = myISPBlocks; + * template using id_to_details = block_type; + * }; + * + * ... + * + * // Derive the V4L2Params class by providing params_traits + * class MyISPParams : public V4L2Params + * { + * public: + * MyISPParams::MyISPParams(Span data) + * : V4L2Params(data, kVersion) + * { + * } + * }; + * + * \endcode + * + * Users of this class can then easily access an ISP configuration block as a + * V4L2ParamsBlock instance. + * + * \code{.cpp} + * + * MyISPParams params(data); + * + * auto awb = params.block(); + * awb->gain00 = ...; + * awb->gain01 = ...; + * awb->gain10 = ...; + * awb->gain11 = ...; + * \endcode + */ + +/** + * \fn V4L2Params::V4L2Params() + * \brief Construct a V4L2Params + * \param[in] data Reference to the v4l2-buffer memory mapped area + * \param[in] version The ISP parameters version the implementation supports + */ + +/** + * \fn V4L2Params::size() + * \brief Retrieve the used size of the parameters buffer (in bytes) + * + * The parameters buffer size is mostly used to populate the v4l2_buffer + * bytesused field before queueing the buffer to the ISP. + * + * \return The number of bytes occupied by the ISP configuration parameters + */ + +/** + * \fn V4L2Params::block() + * \brief Retrieve the location of an ISP configuration block a returns it + * \return A V4L2ParamsBlock instance that points to the ISP configuration block + */ + +/** + * \fn V4L2Params::block(typename Traits::id_type type, unsigned int blockType, size_t blockSize) + * \brief Populate an ISP configuration block a returns a reference to its + * memory + * \param[in] type The ISP block identifier enumerated by the IPA module + * \param[in] blockType The kernel-defined ISP block identifier, used to + * populate the block header + * \param[in] blockSize The ISP block size, used to populate the block header + * + * Initialize the block header with \a blockType and \a blockSize and + * returns a reference to the memory used to store an ISP configuration block. + * + * IPA modules that derive the V4L2Params class shall use this function to + * retrieve the memory area that will be used to construct a V4L2ParamsBlock + * before returning it to the caller. + */ + +/** + * \var V4L2Params::data_ + * \brief The ISP parameters buffer memory + */ + +/** + * \var V4L2Params::used_ + * \brief The number of bytes used in the parameters buffer + */ + +/** + * \var V4L2Params::blocks_ + * \brief Cache of ISP configuration blocks + */ + +} /* namespace ipa */ + +} /* namespace libcamera */ diff --git a/src/ipa/libipa/v4l2_params.h b/src/ipa/libipa/v4l2_params.h new file mode 100644 index 0000000000000000000000000000000000000000..c85552ec50ae6f3a1bd8a0fede3c793df2f6da4d --- /dev/null +++ b/src/ipa/libipa/v4l2_params.h @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Ideas On Board + * + * V4L2 Parameters + */ + +#pragma once + +#include +#include +#include + +#include + +#include + +namespace libcamera { + +namespace ipa { + +template +class V4L2ParamsBlock +{ +public: + V4L2ParamsBlock(const Span data) + : data_(data) + { + } + + virtual ~V4L2ParamsBlock() {} + + virtual void setEnabled(bool enabled) + { + struct v4l2_params_block_header *header = + reinterpret_cast(data_.data()); + + header->flags &= ~(V4L2_PARAMS_FL_BLOCK_ENABLE | + V4L2_PARAMS_FL_BLOCK_DISABLE); + header->flags |= enabled ? V4L2_PARAMS_FL_BLOCK_ENABLE + : V4L2_PARAMS_FL_BLOCK_DISABLE; + } + + virtual const T *operator->() const + { + return reinterpret_cast(data_.data()); + } + + virtual T *operator->() + { + return reinterpret_cast(data_.data()); + } + + virtual const T &operator*() const + { + return *reinterpret_cast(data_.data()); + } + + virtual T &operator*() + { + return *reinterpret_cast(data_.data()); + } + +protected: + Span data_; +}; + +template +class V4L2Params +{ +public: + V4L2Params(Span data, unsigned int version) + : data_(data) + { + struct v4l2_params_buffer *cfg = + reinterpret_cast(data_.data()); + cfg->data_size = 0; + cfg->version = version; + used_ = offsetof(struct v4l2_params_buffer, data); + } + + size_t size() const { return used_; } + + template + auto block() + { + using Details = typename Traits::template id_to_details; + + using Type = typename Details::type; + constexpr auto kernelId = Details::blockType; + + auto data = block(Id, kernelId, sizeof(Type)); + return V4L2ParamsBlock(data); + } + +protected: + Span block(typename Traits::id_type type, + unsigned int blockType, size_t blockSize) + { + /* + * Look up the block in the cache first. If an algorithm + * requests the same block type twice, it should get the same + * block. + */ + auto cacheIt = blocks_.find(type); + if (cacheIt != blocks_.end()) + return cacheIt->second; + + /* Make sure we don't run out of space. */ + if (blockSize > data_.size() - used_) + return {}; + + /* Allocate a new block, clear its memory, and initialize its header. */ + Span block = data_.subspan(used_, blockSize); + used_ += blockSize; + + struct v4l2_params_buffer *cfg = + reinterpret_cast(data_.data()); + cfg->data_size += blockSize; + + memset(block.data(), 0, block.size()); + + struct v4l2_params_block_header *header = + reinterpret_cast(block.data()); + header->type = blockType; + header->size = block.size(); + + /* Update the cache. */ + blocks_[type] = block; + + return block; + } + + Span data_; + size_t used_; + + std::map> blocks_; +}; + +} /* namespace ipa */ + +} /* namespace libcamera */ diff --git a/src/ipa/rkisp1/params.cpp b/src/ipa/rkisp1/params.cpp index 5edb36c91b87859d02c0a8b41efe977ff048def5..7040207c26557aa278050a1f7232cc6c380505b1 100644 --- a/src/ipa/rkisp1/params.cpp +++ b/src/ipa/rkisp1/params.cpp @@ -35,7 +35,7 @@ struct BlockTypeInfo { #define RKISP1_BLOCK_TYPE_ENTRY(block, id, type, category, bit) \ { BlockType::block, { \ RKISP1_EXT_PARAMS_BLOCK_TYPE_##id, \ - sizeof(struct rkisp1_cif_isp_##type##_config), \ + sizeof(struct rkisp1_ext_params_##type##_config), \ offsetof(struct rkisp1_params_cfg, category.type##_config), \ RKISP1_CIF_ISP_MODULE_##bit, \ } } @@ -49,7 +49,7 @@ struct BlockTypeInfo { #define RKISP1_BLOCK_TYPE_ENTRY_EXT(block, id, type) \ { BlockType::block, { \ RKISP1_EXT_PARAMS_BLOCK_TYPE_##id, \ - sizeof(struct rkisp1_cif_isp_##type##_config), \ + sizeof(struct rkisp1_ext_params_##type##_config), \ 0, 0, \ } } @@ -79,56 +79,6 @@ const std::map kBlockTypeInfo = { } /* namespace */ -RkISP1ParamsBlockBase::RkISP1ParamsBlockBase(RkISP1Params *params, BlockType type, - const Span &data) - : params_(params), type_(type) -{ - if (params_->format() == V4L2_META_FMT_RK_ISP1_EXT_PARAMS) { - header_ = data.subspan(0, sizeof(rkisp1_ext_params_block_header)); - data_ = data.subspan(sizeof(rkisp1_ext_params_block_header)); - } else { - data_ = data; - } -} - -void RkISP1ParamsBlockBase::setEnabled(bool enabled) -{ - /* - * For the legacy fixed format, blocks are enabled in the top-level - * header. Delegate to the RkISP1Params class. - */ - if (params_->format() == V4L2_META_FMT_RK_ISP1_PARAMS) - return params_->setBlockEnabled(type_, enabled); - - /* - * For the extensible format, set the enable and disable flags in the - * block header directly. - */ - struct rkisp1_ext_params_block_header *header = - reinterpret_cast(header_.data()); - header->flags &= ~(RKISP1_EXT_PARAMS_FL_BLOCK_ENABLE | - RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE); - header->flags |= enabled ? RKISP1_EXT_PARAMS_FL_BLOCK_ENABLE - : RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE; -} - -RkISP1Params::RkISP1Params(uint32_t format, Span data) - : format_(format), data_(data), used_(0) -{ - if (format_ == V4L2_META_FMT_RK_ISP1_EXT_PARAMS) { - struct rkisp1_ext_params_cfg *cfg = - reinterpret_cast(data.data()); - - cfg->version = RKISP1_EXT_PARAM_BUFFER_V1; - cfg->data_size = 0; - - used_ += offsetof(struct rkisp1_ext_params_cfg, data); - } else { - memset(data.data(), 0, data.size()); - used_ = sizeof(struct rkisp1_params_cfg); - } -} - void RkISP1Params::setBlockEnabled(BlockType type, bool enabled) { const BlockTypeInfo &info = kBlockTypeInfo.at(type); @@ -178,44 +128,7 @@ Span RkISP1Params::block(BlockType type) return data_.subspan(info.offset, info.size); } - /* - * For the extensible format, allocate memory for the block, including - * the header. Look up the block in the cache first. If an algorithm - * requests the same block type twice, it should get the same block. - */ - auto cacheIt = blocks_.find(type); - if (cacheIt != blocks_.end()) - return cacheIt->second; - - /* Make sure we don't run out of space. */ - size_t size = sizeof(struct rkisp1_ext_params_block_header) - + ((info.size + 7) & ~7); - if (size > data_.size() - used_) { - LOG(RkISP1Params, Error) - << "Out of memory to allocate block type " - << utils::to_underlying(type); - return {}; - } - - /* Allocate a new block, clear its memory, and initialize its header. */ - Span block = data_.subspan(used_, size); - used_ += size; - - struct rkisp1_ext_params_cfg *cfg = - reinterpret_cast(data_.data()); - cfg->data_size += size; - - memset(block.data(), 0, block.size()); - - struct rkisp1_ext_params_block_header *header = - reinterpret_cast(block.data()); - header->type = info.type; - header->size = block.size(); - - /* Update the cache. */ - blocks_[type] = block; - - return block; + return V4L2Params::block(type, info.type, info.size); } } /* namespace ipa::rkisp1 */ diff --git a/src/ipa/rkisp1/params.h b/src/ipa/rkisp1/params.h index 2e60528d102ec44a31417d4b146e74cace363efa..a7fbbc581c6df8a92dcc4fcfe1e620da6c469915 100644 --- a/src/ipa/rkisp1/params.h +++ b/src/ipa/rkisp1/params.h @@ -7,13 +7,10 @@ #pragma once -#include -#include - #include +#include -#include -#include +#include namespace libcamera { @@ -49,115 +46,143 @@ template struct block_type { }; -#define RKISP1_DEFINE_BLOCK_TYPE(blockType, blockStruct) \ +#define RKISP1_DEFINE_BLOCK_TYPE(blockType, blockStruct, id) \ template<> \ struct block_type { \ using type = struct rkisp1_cif_isp_##blockStruct##_config; \ + static constexpr rkisp1_ext_params_block_type blockType = \ + RKISP1_EXT_PARAMS_BLOCK_TYPE_##id; \ }; -RKISP1_DEFINE_BLOCK_TYPE(Bls, bls) -RKISP1_DEFINE_BLOCK_TYPE(Dpcc, dpcc) -RKISP1_DEFINE_BLOCK_TYPE(Sdg, sdg) -RKISP1_DEFINE_BLOCK_TYPE(AwbGain, awb_gain) -RKISP1_DEFINE_BLOCK_TYPE(Flt, flt) -RKISP1_DEFINE_BLOCK_TYPE(Bdm, bdm) -RKISP1_DEFINE_BLOCK_TYPE(Ctk, ctk) -RKISP1_DEFINE_BLOCK_TYPE(Goc, goc) -RKISP1_DEFINE_BLOCK_TYPE(Dpf, dpf) -RKISP1_DEFINE_BLOCK_TYPE(DpfStrength, dpf_strength) -RKISP1_DEFINE_BLOCK_TYPE(Cproc, cproc) -RKISP1_DEFINE_BLOCK_TYPE(Ie, ie) -RKISP1_DEFINE_BLOCK_TYPE(Lsc, lsc) -RKISP1_DEFINE_BLOCK_TYPE(Awb, awb_meas) -RKISP1_DEFINE_BLOCK_TYPE(Hst, hst) -RKISP1_DEFINE_BLOCK_TYPE(Aec, aec) -RKISP1_DEFINE_BLOCK_TYPE(Afc, afc) -RKISP1_DEFINE_BLOCK_TYPE(CompandBls, compand_bls) -RKISP1_DEFINE_BLOCK_TYPE(CompandExpand, compand_curve) -RKISP1_DEFINE_BLOCK_TYPE(CompandCompress, compand_curve) -RKISP1_DEFINE_BLOCK_TYPE(Wdr, wdr) +RKISP1_DEFINE_BLOCK_TYPE(Bls, bls, BLS) +RKISP1_DEFINE_BLOCK_TYPE(Dpcc, dpcc, DPCC) +RKISP1_DEFINE_BLOCK_TYPE(Sdg, sdg, SDG) +RKISP1_DEFINE_BLOCK_TYPE(AwbGain, awb_gain, AWB_GAIN) +RKISP1_DEFINE_BLOCK_TYPE(Flt, flt, FLT) +RKISP1_DEFINE_BLOCK_TYPE(Bdm, bdm, BDM) +RKISP1_DEFINE_BLOCK_TYPE(Ctk, ctk, CTK) +RKISP1_DEFINE_BLOCK_TYPE(Goc, goc, GOC) +RKISP1_DEFINE_BLOCK_TYPE(Dpf, dpf, DPF) +RKISP1_DEFINE_BLOCK_TYPE(DpfStrength, dpf_strength, DPF_STRENGTH) +RKISP1_DEFINE_BLOCK_TYPE(Cproc, cproc, CPROC) +RKISP1_DEFINE_BLOCK_TYPE(Ie, ie, IE) +RKISP1_DEFINE_BLOCK_TYPE(Lsc, lsc, LSC) +RKISP1_DEFINE_BLOCK_TYPE(Awb, awb_meas, AWB_MEAS) +RKISP1_DEFINE_BLOCK_TYPE(Hst, hst, HST_MEAS) +RKISP1_DEFINE_BLOCK_TYPE(Aec, aec, AEC_MEAS) +RKISP1_DEFINE_BLOCK_TYPE(Afc, afc, AFC_MEAS) +RKISP1_DEFINE_BLOCK_TYPE(CompandBls, compand_bls, COMPAND_BLS) +RKISP1_DEFINE_BLOCK_TYPE(CompandExpand, compand_curve, COMPAND_EXPAND) +RKISP1_DEFINE_BLOCK_TYPE(CompandCompress, compand_curve, COMPAND_COMPRESS) +RKISP1_DEFINE_BLOCK_TYPE(Wdr, wdr, WDR) + +struct params_traits { + using id_type = BlockType; + + template + using id_to_details = block_type; +}; } /* namespace details */ -class RkISP1Params; +template +class RkISP1ParamsBlock; -class RkISP1ParamsBlockBase +class RkISP1Params : public V4L2Params { public: - RkISP1ParamsBlockBase(RkISP1Params *params, BlockType type, - const Span &data); + static constexpr unsigned int kVersion = RKISP1_EXT_PARAM_BUFFER_V1; + + RkISP1Params(uint32_t format, Span data) + : V4L2Params(data, kVersion), format_(format) + { + if (format_ == V4L2_META_FMT_RK_ISP1_PARAMS) { + memset(data.data(), 0, data.size()); + used_ = sizeof(struct rkisp1_params_cfg); + } + } + + template + auto block() + { + using Type = typename details::block_type::type; - Span data() const { return data_; } + return RkISP1ParamsBlock(this, id, block(id)); + } - void setEnabled(bool enabled); + uint32_t format() const { return format_; } + void setBlockEnabled(BlockType type, bool enabled); private: - LIBCAMERA_DISABLE_COPY(RkISP1ParamsBlockBase) + Span block(BlockType type); - RkISP1Params *params_; - BlockType type_; - Span header_; - Span data_; + uint32_t format_; }; -template -class RkISP1ParamsBlock : public RkISP1ParamsBlockBase +template +class RkISP1ParamsBlock : public V4L2ParamsBlock { public: - using Type = typename details::block_type::type; - - RkISP1ParamsBlock(RkISP1Params *params, const Span &data) - : RkISP1ParamsBlockBase(params, B, data) + RkISP1ParamsBlock(RkISP1Params *params, BlockType type, + const Span data) + : V4L2ParamsBlock(data) { + params_ = params; + type_ = type; + + /* + * cifData_ points to the actual configuration data + * (struct rkisp1_cif_isp_*) which is not prefixed by any header, + * for the legacy fixed format. + */ + if (params_->format() == V4L2_META_FMT_RK_ISP1_PARAMS) + cifData_ = data; + else + cifData_ = data.subspan(sizeof(v4l2_params_block_header)); } - const Type *operator->() const + void setEnabled(bool enabled) override { - return reinterpret_cast(data().data()); + /* + * For the legacy fixed format, blocks are enabled in the + * top-level header. Delegate to the RkISP1Params class. + */ + if (params_->format() == V4L2_META_FMT_RK_ISP1_PARAMS) + return params_->setBlockEnabled(type_, enabled); + + return V4L2ParamsBlock::setEnabled(enabled); } - Type *operator->() + /* + * Override the dereference operators to return a reference to the + * actual configuration data (struct rkisp1_cif_isp_*) skipping the + * 'v4l2_params_block_header' header. + */ + + virtual const T *operator->() const override { - return reinterpret_cast(data().data()); + return reinterpret_cast(cifData_.data()); } - const Type &operator*() const & + virtual T *operator->() override { - return *reinterpret_cast(data().data()); + return reinterpret_cast(cifData_.data()); } - Type &operator*() & + virtual const T &operator*() const override { - return *reinterpret_cast(data().data()); + return *reinterpret_cast(cifData_.data()); } -}; - -class RkISP1Params -{ -public: - RkISP1Params(uint32_t format, Span data); - template - RkISP1ParamsBlock block() + virtual T &operator*() override { - return RkISP1ParamsBlock(this, block(B)); + return *reinterpret_cast(cifData_.data()); } - uint32_t format() const { return format_; } - size_t size() const { return used_; } - private: - friend class RkISP1ParamsBlockBase; - - Span block(BlockType type); - void setBlockEnabled(BlockType type, bool enabled); - - uint32_t format_; - - Span data_; - size_t used_; - - std::map> blocks_; + RkISP1Params *params_; + BlockType type_; + Span cifData_; }; } /* namespace ipa::rkisp1 */ From patchwork Fri Sep 26 14:39:37 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24477 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id F0FDBC328C for ; Fri, 26 Sep 2025 14:40:06 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A26ED6B608; Fri, 26 Sep 2025 16:40:04 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="u7im/3QZ"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B7BEB6B5F8 for ; Fri, 26 Sep 2025 16:39:57 +0200 (CEST) Received: from [192.168.1.100] (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3C798152D; Fri, 26 Sep 2025 16:38:31 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758897511; bh=vI0N+DyqacjJISp6qENr/0VSu9nG56sjWISRuOOKRrE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=u7im/3QZmGgZmRPmKoBmRb4Gg9uaZG1/PPtU3r0+7/tXuy5FojogIm8iHzSOz6nk8 j2nMbM7m1uJ4258ojn0AAwD+PdynVyBkq8OzLq5D0mH5hclaGZ8RWemuv5TMhqVDAf TuVOfAPTkQ61Llk1pwWroHkFFL52PWTlla5O5G14= From: Jacopo Mondi Date: Fri, 26 Sep 2025 16:39:37 +0200 Subject: [PATCH v3 5/5] ipa: mali-c55: Introduce MaliC55Params MIME-Version: 1.0 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 , Antoine Bouyer X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=25052; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=vI0N+DyqacjJISp6qENr/0VSu9nG56sjWISRuOOKRrE=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBo1qW2BQMiwT1ZDD+gIwmQHI4W6YcdV968DuOPo w8yixUScVaJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaNaltgAKCRByNAaPFqFW PDBHEAC6lXOSs8sWj0iFMp9FLcc1jdleLqeEWUkl1p/kQD2V6KHpKpPqBnKavJFXuTZQ2cfRxeF WuM93EF1RyGbauOficv0ARt7DNJ1GARXZh8VomCIc5y2u4MZ9nPJ/dyaUVoUs1IE8ezyzu+sAP6 15abuR79aj8JKaSyf+nBt1vq406Abw74xw/dh/FUxurdLoURuiAvvOXjxTg2i53PlbjxFMn4Hmx KDfq2g5rnRIZYcEptKVVYe2Gnwwlb0HjnBWYjBqvQ49KV1r7jUZ7lfALQTaExreInEe2qXm6cE6 iU5JoMKLe1YIEXTBqKaoVuDbXjkawFuY3cdeGPULzY4awO/iKbreRbvMSNyWDo1LoUfFYMd0jH3 OFJUvsahz/HxkReOnHPpcaeNbBep2FbCN0TnoB02a7eBbCyVXh3XIF5Cty39FZ77S8CWrFI8HxJ saf4/84iu8HLdrIztnTSBmJG1ruzVsDmESvpBvgrnfW7DoZkzfnhjRMjAzm95CvCjc8/QYUhVX2 hTDGiku15FMXBT6PXJITud6uM4SjQCuuuEcUJuOOXBA17+pUjkGyHXM00aXk1aOomv4WOnD9/pQ FTQ+XbTPoXCGtfT9bpnUPjIfHAUWLE6M68YX46ZTZiDPAdDSP0dAj+SGeGjy1NBjjhfzlLwJC3n gN70bAKDswsEfLQ== X-Developer-Key: i=jacopo.mondi@ideasonboard.com; a=openpgp; fpr=72392EDC88144A65C701EA9BA5826A2587AD026B X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Implement MaliC55Params to derive from V4L2Params and use the new helpers in the Mali C55 IPA algorithms implementation. Signed-off-by: Jacopo Mondi Tested-By: Antoine Bouyer --- 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 | 83 +++++++++++++++++++++++++++++++++++ 11 files changed, 197 insertions(+), 172 deletions(-) diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp index da47cf15be49327a592e850817f2863ab62cb404..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(); + 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() : + params->block(); /* 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() : + params->block(); /* 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 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 = ¶ms->data[params->data_size]; - params->data_size += fillGainParamBlock(context, frameContext, block); + fillGainParamBlock(context, frameContext, params); if (frame > 0) return; - block.data = ¶ms->data[params->data_size]; - params->data_size += fillParamsBuffer(block, - MALI_C55_PARAM_BLOCK_AEXP_HIST); - - block.data = ¶ms->data[params->data_size]; - params->data_size += fillWeightsArrayBuffer(block, - MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS); - - block.data = ¶ms->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 = ¶ms->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(); + + 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(); /* 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 = ¶ms->data[params->data_size]; - - params->data_size += fillGainsParamBlock(block, context, frameContext); + fillGainsParamBlock(params, context, frameContext); if (frame > 0) return; - block.data = ¶ms->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 = ¶ms->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(); + 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(); - 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(); + + 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 Lsc::findBankAndAlpha(uint32_t ct) const @@ -170,7 +162,7 @@ std::tuple 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 = ¶ms->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 = ¶ms->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 findBankAndAlpha(uint32_t ct) const; std::vector mesh_ = std::vector(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( - 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, ¶ms); - 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 #include "ipa_context.h" +#include "params.h" namespace libcamera { namespace ipa::mali_c55 { using Module = ipa::Module; + 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..bb26da19a8f1336eeed91989a6c13e7630c6e5f4 --- /dev/null +++ b/src/ipa/mali-c55/params.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Ideas On Board + * + * Mali C55 ISP Parameters + */ + +#pragma once + +#include +#include + +#include + +namespace libcamera { + +namespace ipa::mali_c55 { + +enum class MaliC55Blocks { + Bls, + AexpHist, + AexpHistWeights, + AexpIhist, + AexpIhistWeights, + Dgain, + AwbGains, + AwbConfig, + MeshShadingConfig, + MeshShadingSel, +}; + +namespace details { + +template +struct block_type { +}; + +#define MALI_C55_DEFINE_BLOCK_TYPE(id, cfgType, blkType) \ +template<> \ +struct block_type { \ + 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 + using id_to_details = block_type; +}; + +} /* namespace details */ + +class MaliC55Params : public V4L2Params +{ +public: + static constexpr unsigned int kVersion = MALI_C55_PARAM_BUFFER_V1; + + MaliC55Params(Span data) + : V4L2Params(data, kVersion) + { + } +}; + +} /* namespace ipa::mali_c55 */ + +} /* namespace libcamera */