From patchwork Tue Mar 31 16:36:29 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 26391 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 51105C32BB for ; Tue, 31 Mar 2026 16:36:55 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4296762D1E; Tue, 31 Mar 2026 18:36:53 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Nh3M9lfT"; 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 51D6D6274D for ; Tue, 31 Mar 2026 18:36:50 +0200 (CEST) Received: from [100.93.44.16] (net-93-65-100-155.cust.vodafonedsl.it [93.65.100.155]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A24CC2451; Tue, 31 Mar 2026 18:35:27 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1774974927; bh=cPNFG01nfL/fFep4yGdJzWBDfo5rH8weIzKgIeOBJvw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Nh3M9lfTIByX0Llxg9jN4D12S0jMY/ZtQ16hfQOuW97GvUqhG15DFuejKtEduZGb3 3yAyDUNaLLK6OUTcmWm/DDaQPd8f+NhFz6Hoe9j1OJBNjaQ/LlF9Cg9ODJ2ymLL/Pf jB847wMaYFuOiHcARTHsJWBYTXtu2cEL906kZs/4= From: Jacopo Mondi Date: Tue, 31 Mar 2026 18:36:29 +0200 Subject: [PATCH v7 1/8] libcamera: mali-c55: Add RZG2LCRU class MIME-Version: 1.0 Message-Id: <20260331-mali-cru-v7-1-4caedc898a0e@ideasonboard.com> References: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> In-Reply-To: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> To: Daniel Scally , libcamera-devel@lists.libcamera.org Cc: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Jacopo Mondi X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=9802; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=l/27g48AuepEqwXR256i1nph+XEQELQu6hC3lLzVaV8=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBpy/ggDaZR1rfwO6TIswdXx8cqA5oAezK4ngsri YcozMuCgz+JAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCacv4IAAKCRByNAaPFqFW PHIAD/4pzNNXIz3s3iJ/TeKTjKrJHxvPZRTHKw0387We8SacFxRQPzBStrc7pqV443TnM2NSgQm eik1JKbBV7aI+O8fFBSsc3u7Sylg5rg+CRC/fLh/24E30xog9q7//QCFjbjAL2xXis2zFy5tZzr olOW83MbAuukAToO0qaEfAGMTiruDU/uTUc4PwcR+sjcJ1l8vHtp5DJA2kzgs/P2BGcdCMYSiOA 8O0M4i7ZCTjdiNqn96Px1f+rFAJ7iQ9/CPP8MzOe/dj1DO6euBxhl9otZk8iB5H8L7Zt3XDlq54 2dIpenaPPyvy+9VOVeNnqic+13h9c5ghfgcOi3w5VIuxmt0VwPohvyJ2JE8JceZhK08hYXClYmf msYeUz/12nacS6KixHEumNuGTBso9UX2PweRAqTQ2LApQaeYMiFkPJIRdB7qnWZeyrNUnWQ7UE2 Ib9iGqlhSc3B+EpT0xwW/iQ/nA2oUryojscdeY6JVVtuVE1FbbfJNL92aYoPhvICL97zZ9yNSsl WW8ukSlG7FYKfMe4sTMVLJjw7142TxV6jHxE7eHDjaJxlxkjpPbd9a2jDOLQ/iIcGcxB7aRcgjJ poTTWHQapUPBwXiaJkfmph4QkNPOgCiinL6RpGopUpRPJEDhf6nnN0s8CMR/9n8DG5YWtEwy/ow t7qvAfXzKA43MdQ== 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" From: Daniel Scally Add a class allowing us to control the RZ/G2L Camera Receiver Unit. The class is named after the media device it handles, which is called "rzg2l_cru" but the CRU is actually found in other SoCs than the RZ/G2L one, such as the RZ/V2H(P). The RZG2LCRU class models the CSI-2 receiver found on those SoCs and allows to add support for memory-to-memory operations on the RZ/V2H(P) SoC which integrates a Mali-C55 ISP and a specialized DMA engine named IVC that feeds images from memory, where the CRU has saved them. Signed-off-by: Daniel Scally Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/mali-c55/meson.build | 3 +- src/libcamera/pipeline/mali-c55/rzg2l-cru.cpp | 253 ++++++++++++++++++++++++++ src/libcamera/pipeline/mali-c55/rzg2l-cru.h | 70 +++++++ 3 files changed, 325 insertions(+), 1 deletion(-) diff --git a/src/libcamera/pipeline/mali-c55/meson.build b/src/libcamera/pipeline/mali-c55/meson.build index eba8e5a39054..4e768242602e 100644 --- a/src/libcamera/pipeline/mali-c55/meson.build +++ b/src/libcamera/pipeline/mali-c55/meson.build @@ -1,5 +1,6 @@ # SPDX-License-Identifier: CC0-1.0 libcamera_internal_sources += files([ - 'mali-c55.cpp' + 'mali-c55.cpp', + 'rzg2l-cru.cpp', ]) diff --git a/src/libcamera/pipeline/mali-c55/rzg2l-cru.cpp b/src/libcamera/pipeline/mali-c55/rzg2l-cru.cpp new file mode 100644 index 000000000000..9cb7cc3f10c6 --- /dev/null +++ b/src/libcamera/pipeline/mali-c55/rzg2l-cru.cpp @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Ideas on Board Oy + * + * Pipine handler element for the Renesas RZ/G2L Camera Receiver Unit + */ + +#include "rzg2l-cru.h" + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include "libcamera/internal/bayer_format.h" +#include "libcamera/internal/camera_sensor.h" +#include "libcamera/internal/framebuffer.h" +#include "libcamera/internal/media_device.h" +#include "libcamera/internal/request.h" + +namespace libcamera { + +static const std::map bitDepthToFmt{ + { 10, V4L2PixelFormat(V4L2_PIX_FMT_RAW_CRU10) }, + { 12, V4L2PixelFormat(V4L2_PIX_FMT_RAW_CRU12) }, + { 14, V4L2PixelFormat(V4L2_PIX_FMT_RAW_CRU14) }, +}; + +LOG_DEFINE_CATEGORY(RZG2LCRU) + +FrameBuffer *RZG2LCRU::queueBuffer(Request *request) +{ + FrameBuffer *buffer; + + if (availableBuffers_.empty()) { + LOG(RZG2LCRU, Debug) << "CRU buffer underrun"; + return nullptr; + } + + buffer = availableBuffers_.back(); + + int ret = output_->queueBuffer(buffer); + if (ret) { + LOG(RZG2LCRU, Error) << "Failed to queue buffer to CRU"; + return nullptr; + } + + availableBuffers_.pop_back(); + buffer->_d()->setRequest(request); + + return buffer; +} + +void RZG2LCRU::returnBuffer(FrameBuffer *buffer) +{ + auto it = std::find_if(buffers_.begin(), buffers_.end(), + [&](const auto &b) { return b.get() == buffer; }); + ASSERT(it != buffers_.end()); + + availableBuffers_.push_back(buffer); +} + +int RZG2LCRU::start(unsigned int bufferCount) +{ + int ret = output_->exportBuffers(bufferCount, &buffers_); + if (ret < 0) + return ret; + + utils::scope_exit bufferGuard([&] { freeBuffers(); }); + + ret = output_->importBuffers(bufferCount); + if (ret) + return ret; + + for (std::unique_ptr &buffer : buffers_) + availableBuffers_.push_back(buffer.get()); + + ret = output_->streamOn(); + if (ret) + return ret; + + bufferGuard.release(); + + return 0; +} + +int RZG2LCRU::stop() +{ + return output_->streamOff(); +} + +int RZG2LCRU::freeBuffers() +{ + availableBuffers_.clear(); + buffers_.clear(); + + return output_->releaseBuffers(); +} + +int RZG2LCRU::configure(V4L2SubdeviceFormat *subdevFormat, V4L2DeviceFormat *inputFormat) +{ + /* + * Set format on the sensor and propagate it up to the CRU video + * device. + */ + + int ret = sensor_->setFormat(subdevFormat); + if (ret) + return ret; + + ret = csi2_->setFormat(0, subdevFormat); + if (ret) + return ret; + + ret = csi2_->getFormat(1, subdevFormat); + if (ret) + return ret; + + ret = cru_->setFormat(0, subdevFormat); + if (ret) + return ret; + + ret = cru_->getFormat(1, subdevFormat); + if (ret) + return ret; + + /* + * The capture device needs to be set with a format that can be produced + * from the mbus code of the subdevFormat. The CRU and IVC use bayer + * order agnostic pixel formats, so all we need to do is find the right + * bitdepth and select the appropriate format. + */ + BayerFormat bayerFormat = BayerFormat::fromMbusCode(subdevFormat->code); + if (!bayerFormat.isValid()) + return -EINVAL; + + V4L2DeviceFormat captureFormat; + captureFormat.fourcc = bitDepthToFmt.at(bayerFormat.bitDepth); + captureFormat.size = subdevFormat->size; + + ret = output_->setFormat(&captureFormat); + if (ret) + return ret; + + /* + * We return the format that we set against the output device, as the + * same format will also need to be set against the Input Video Control + * Block device. + */ + *inputFormat = captureFormat; + + return 0; +} + +void RZG2LCRU::initCRUSizes() +{ + Size maxCSI2Size; + + /* + * Get the maximum supported size on the CSI-2 receiver. We need to + * query the kernel interface as the size limits differ from RZ/G2L + * (2800x4095) and RZ/V2H (4096x4096). + */ + V4L2Subdevice::Formats csi2Formats = csi2_->formats(0); + if (csi2Formats.empty()) + return; + + for (const auto &format : csi2Formats) { + for (const auto &range : format.second) { + if (range.max > maxCSI2Size) + maxCSI2Size = range.max; + } + } + + /* + * Enumerate the sensor supported resolutions and filter out the ones + * larger than the maximum supported CSI-2 receiver input size. + */ + V4L2Subdevice::Formats formats = sensor_->device()->formats(0); + if (formats.empty()) + return; + + for (const auto &format : formats) { + for (const auto &range : format.second) { + const Size &max = range.max; + + if (max.width > maxCSI2Size.width || + max.height > maxCSI2Size.height) + continue; + + csi2Sizes_.push_back(max); + } + } + + /* Sort in increasing order and remove duplicates. */ + std::sort(csi2Sizes_.begin(), csi2Sizes_.end()); + auto last = std::unique(csi2Sizes_.begin(), csi2Sizes_.end()); + csi2Sizes_.erase(last, csi2Sizes_.end()); + + csi2Resolution_ = csi2Sizes_.back(); +} + +int RZG2LCRU::init(const MediaDevice *media) +{ + static const std::regex cruRegex("cru-ip-[0-9a-f]{8}.cru[0-9]"); + static const std::regex csi2Regex("csi-[0-9a-f]{8}.csi2"); + + csi2_ = V4L2Subdevice::fromEntityName(media, csi2Regex); + if (!csi2_) + return -ENODEV; + + int ret = csi2_->open(); + if (ret) + return ret; + + const std::vector &pads = csi2_->entity()->pads(); + if (pads.empty()) + return -ENODEV; + + /* The receiver has a single sink pad at index 0 */ + MediaPad *sink = pads[0]; + const std::vector &links = sink->links(); + if (links.empty()) + return -ENODEV; + + MediaLink *link = links[0]; + sensor_ = CameraSensorFactoryBase::create(link->source()->entity()); + if (!sensor_) + return -ENODEV; + + cru_ = V4L2Subdevice::fromEntityName(media, cruRegex); + ret = cru_->open(); + if (ret) + return ret; + + output_ = V4L2VideoDevice::fromEntityName(media, "CRU output"); + ret = output_->open(); + if (ret) + return ret; + + initCRUSizes(); + + return 0; +} + +} /* namespace libcamera */ diff --git a/src/libcamera/pipeline/mali-c55/rzg2l-cru.h b/src/libcamera/pipeline/mali-c55/rzg2l-cru.h new file mode 100644 index 000000000000..8bd4c027adda --- /dev/null +++ b/src/libcamera/pipeline/mali-c55/rzg2l-cru.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Ideas on Board Oy + * + * Pipine handler element for the Renesas RZ/G2L Camera Receiver Unit + */ + +#pragma once + +#include +#include + +#include + +#include "libcamera/internal/v4l2_subdevice.h" +#include "libcamera/internal/v4l2_videodevice.h" + +namespace libcamera { + +class CameraSensor; +class FrameBuffer; +class MediaDevice; +class Request; +class Size; + +class RZG2LCRU +{ +public: + RZG2LCRU() = default; + + const std::vector &sizes() const + { + return csi2Sizes_; + } + + int init(const MediaDevice *media); + const Size &resolution() const + { + return csi2Resolution_; + } + + CameraSensor *sensor() const { return sensor_.get(); } + V4L2Subdevice *csi2() const { return csi2_.get(); } + V4L2Subdevice *cru() const { return cru_.get(); } + V4L2VideoDevice *output() { return output_.get(); } + + int configure(V4L2SubdeviceFormat *subdevFormat, V4L2DeviceFormat *inputFormat); + FrameBuffer *queueBuffer(Request *request); + void returnBuffer(FrameBuffer *buffer); + int freeBuffers(); + + int start(unsigned int bufferCount); + int stop(); + +private: + void initCRUSizes(); + + std::unique_ptr sensor_; + std::unique_ptr csi2_; + std::unique_ptr cru_; + std::unique_ptr output_; + + std::vector> buffers_; + std::vector availableBuffers_; + + std::vector csi2Sizes_; + Size csi2Resolution_; +}; + +} /* namespace libcamera */ From patchwork Tue Mar 31 16:36:30 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 26392 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 15961BDCBD for ; Tue, 31 Mar 2026 16:36:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C684262D18; Tue, 31 Mar 2026 18:36:53 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="A6uvPMF2"; 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 7E2B062D13 for ; Tue, 31 Mar 2026 18:36:50 +0200 (CEST) Received: from [100.93.44.16] (net-93-65-100-155.cust.vodafonedsl.it [93.65.100.155]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id F11E625B5; Tue, 31 Mar 2026 18:35:27 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1774974928; bh=FegylNAS/ZE8S1oZUyAdmGxPOxc4ElLR/QAsnKcxhNE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=A6uvPMF2ndYHCNaiMbSV3nN8kVYk2tILt+nU5/5Z7FVyPL2stpiCfaQKcoF3jl3La KGqKNZmGzKiBsFaEeOAElXTQ/C5bh8LHmoBHkQ/9kkxvbRclNFtBL8ZkWhcViSFJ9Z KiiVHRaDi2pt21XP9iAg/aDTvBVBk9Zntao59sXE= From: Jacopo Mondi Date: Tue, 31 Mar 2026 18:36:30 +0200 Subject: [PATCH v7 2/8] libcamera: utils: Add overloaded visitor helpers MIME-Version: 1.0 Message-Id: <20260331-mali-cru-v7-2-4caedc898a0e@ideasonboard.com> References: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> In-Reply-To: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> To: Daniel Scally , libcamera-devel@lists.libcamera.org Cc: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Jacopo Mondi X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=4147; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=FegylNAS/ZE8S1oZUyAdmGxPOxc4ElLR/QAsnKcxhNE=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBpy/gggN1+I9Fr8/70j8mu3wnLf+8qfdNBQgP4a woRfATOSmyJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCacv4IAAKCRByNAaPFqFW PGIJD/4rhei/fdDAGoOqorP4Xw9R9cT2r/bcXQ4Akere6M4GaX3hYZ8g7QB4F4sMgKAD9OhZTPr DuSQ7Jo7vbyyiT6XQQX2JqcmvYfS8uxUwsIr0VexU0u1QNP/yTjoz8sahNURRIsRwrwQfhCJzTd bfiaGhy/sLpZEdOiu20GrPTEMf+lcx1gZvJRWEIUwlRKfEJO8SkiK51xiWI9bp5YRleW/rs/z/Z KzcKWqWX1+Nto5WU03mH5ItDwRvdu8xBtNLdd10tzO0xlebMI4s4TO0raJm+vZZJmEniogKOfS8 KDSKOD5BeMPMEsjThCm50Ubc//CrjCAdJtZnAnJ6NBDynT1LTyCVdkVJZkMsFYviE5dSGPfD8p+ 97FJQtw79s3xjedKECkoUsAUnv3RUK3b2/MjGQcpaDG10qxbQnKSjZiwmUsp3641l/y4aOqDe6g fx90CkAR/az8QdbmG3+mfk4hwjQriNd4y+MSizAE8KutOvC+s14IaYzT2UV3fAH/GtbtlZ0cGwn X76L4JfQ9uhrhhzvb1+qZwK3ynfzn/uTsMu0gHAMvz8ys1aBe2okREqvvUAILUpbkuC+sfQgJv4 090oLkbo0rAtLg4XCvJVQXngubhA9vnDUGt1eeyTLLnFRFjso5vxQJ3E/cxTCo6yeszdGm+6cJq suj3CG/JAJzEDng== 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" std::visit() allows quite elegant type-matching implementation of the visitor pattern. The 'overloaded' type helpers allow to define a hierarchy of overloaded operator() implementations which can be used by std::visit(). Currently only the Virtual pipeline handler uses this type-matching implementation of std::visit. To prepare to add another user in the Mali C55 pipeline handler move the 'overloaded' helper type to libcamera::utils for easier re-use. Reviewed-by: Barnabás Pőcze Signed-off-by: Jacopo Mondi --- include/libcamera/base/utils.h | 7 ++++++ src/libcamera/base/utils.cpp | 35 ++++++++++++++++++++++++++++++ src/libcamera/pipeline/virtual/virtual.cpp | 10 ++------- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/include/libcamera/base/utils.h b/include/libcamera/base/utils.h index 7083b7ce9ce9..62c7f89c25a1 100644 --- a/include/libcamera/base/utils.h +++ b/include/libcamera/base/utils.h @@ -37,6 +37,13 @@ namespace libcamera { namespace utils { +template +struct overloaded : Ts... { + using Ts::operator()...; +}; +template +overloaded(Ts...) -> overloaded; + const char *basename(const char *path); char *secure_getenv(const char *name); diff --git a/src/libcamera/base/utils.cpp b/src/libcamera/base/utils.cpp index 42a516097be2..836aec87c539 100644 --- a/src/libcamera/base/utils.cpp +++ b/src/libcamera/base/utils.cpp @@ -23,6 +23,41 @@ namespace libcamera { namespace utils { +/** + * \struct overloaded + * \brief Helper type for type-matching std::visit implementations + * \tparam Ts... Template arguments pack of visitors + * + * Expand the template argument pack \a Ts... to provide overloaded \a + * operator() to support type-matching implementations of the visitor design + * pattern using std::visit. + * + * An example is provided by the STL documentation in the form of: + * + * \code{.cpp} + * template struct overloaded : Ts... { using Ts::operator()...; }; + * template overloaded(Ts...) -> overloaded; + * + * using var_t = std::variant; + * std::vector vec = {10, 15l, 1.5, "hello"}; + * + * for (auto& v: vec) { + * std::visit(overloaded { + * [](auto arg) { std::cout << arg << ' '; }, + * [](double arg) { std::cout << std::fixed << arg << ' '; }, + * [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; }, + * }, v); + * \endcode + * + * Use this helper to implement type-matching visitors using std::visit(). + */ + +/** + * \var overloaded(Ts...) -> overloaded + * \brief Deduction guide necessary for C++17 compatibility + * \tparam Ts... Template arguments pack of visitor functions + */ + /** * \brief Strip the directory prefix from the path * \param[in] path The path to process diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp index efd800ebe3d6..e8ef7e524ccf 100644 --- a/src/libcamera/pipeline/virtual/virtual.cpp +++ b/src/libcamera/pipeline/virtual/virtual.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -57,13 +58,6 @@ uint64_t currentTimestamp() } /* namespace */ -template -struct overloaded : Ts... { - using Ts::operator()...; -}; -template -overloaded(Ts...) -> overloaded; - class VirtualCameraConfiguration : public CameraConfiguration { public: @@ -428,7 +422,7 @@ bool PipelineHandlerVirtual::initFrameGenerator(Camera *camera) { auto data = cameraData(camera); auto &frame = data->config_.frame; - std::visit(overloaded{ + std::visit(utils::overloaded{ [&](TestPattern &testPattern) { for (auto &streamConfig : data->streamConfigs_) { if (testPattern == TestPattern::DiagonalLines) From patchwork Tue Mar 31 16:36:31 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 26393 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 3829FC32BB for ; Tue, 31 Mar 2026 16:36:58 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6321762D48; Tue, 31 Mar 2026 18:36:55 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="GMmKJ9oq"; 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 C02E96274D for ; Tue, 31 Mar 2026 18:36:50 +0200 (CEST) Received: from [100.93.44.16] (net-93-65-100-155.cust.vodafonedsl.it [93.65.100.155]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 48A8F31A5; Tue, 31 Mar 2026 18:35:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1774974928; bh=jFpT13cBTk2VgxmG46TrkerQDDgq6237mXTx4G/Gn0A=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=GMmKJ9oqxeNuq6oYdsLDjrTHlxOTm4Z9snQmCtxT/tvrk4GisDBy0Dn6mV4CP5qUI QsCmSxk5Y7RL6deKuV8FAy8mNSf8fkb/CMGE7z4aGvzAn5lpBJfzJyAIbNWt361h3e jYXSz6xRjmHz39hlBH5fudz3CAscCpjc2fLtVBDk= From: Jacopo Mondi Date: Tue, 31 Mar 2026 18:36:31 +0200 Subject: [PATCH v7 3/8] libcamera: mali-c55: Split TPG and Inline camera handling MIME-Version: 1.0 Message-Id: <20260331-mali-cru-v7-3-4caedc898a0e@ideasonboard.com> References: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> In-Reply-To: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> To: Daniel Scally , libcamera-devel@lists.libcamera.org Cc: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Jacopo Mondi X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=16182; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=jFpT13cBTk2VgxmG46TrkerQDDgq6237mXTx4G/Gn0A=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBpy/ggtOwTDBDtAkBzyqIVUMJ6vYUXWFgXZ8OsU yqcYzxDcIOJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCacv4IAAKCRByNAaPFqFW PIR0D/44qvFk5jABHbHra0jtN+kxfVWlGUasd+X70cMRODANSeQkSJXeVV0xrEKE6olswDkqGw1 OY8OHxYJTM8pWyfwyy1Jow6VeRAjlXQBnbCVVkHlhA9THCTmvRMtU83l6DOoE9zSbFR4QNaUVdB JawfvFz8fAYCAie3/uUJBALYCUHWwCwBHYKReR0vl8DUE2DBPJwTaSyCf4fomG3wnuGT9EI1Ahl mOHyZ6xCtAC4idUaCdnQf19x9TyU93HM1cj6ncW3YAeqo5D3rxrubB+6/NA0hWkWI8FsEHSOKg/ +cMcT8vnhnBu8E+HqQcIdrHUF2r9Jm3zCMv3b/Sd+HEK46IeZrJ+qe/kbOzqWkElW3Vts5vo0h7 Bv6Mk7w4oge+WzYT7QEA0Wz/qukGnzYyqkDa5onWUFopLsHbwmHDZnfZ9VkSR6Xs6mvOTMT+OXY ovreGNNY58LUDzqosGNoMfxuWZqjYjfAJReqH9S3NohkaNvistyI1HQ5dLSLNgLC31k0ao+6FIJ Q86MyH+x+uiqMDQmAvox4AfPWtmzXJdqNLyhDFTSHNW/q1yNWJkmkbBu/29fPjYSCVfR8nh3vWB mazQKTprmTyz6aaDoK/VS3yJoqPYETVgQKlGLg46rNYdqUs862Hp/Jo4iyrKecbqtL8PeJyNCT+ LRmJyNzw9zQ9eSg== 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" In order to prepare to support memory input cameras, split the handling of the TPG and Inline camera cases. The Mali C55 pipeline handler uses the entity and subdevice stored in the CameraData to support both the handling of the TPG and of the Inline (CSI-2 + sensor) use cases. Adding support for memory cameras by using the CRU unit would add yet-another special case making the code harder to follow and more prone to errors. Split the handling of the TPG and Inline cameras by introducing an std::variant<> variable and to deflect the functions called on the camera data to the correct type by using overloaded std::visit<>(). Signed-off-by: Jacopo Mondi Reviewed-by: Barnabás Pőcze --- src/libcamera/pipeline/mali-c55/mali-c55.cpp | 278 ++++++++++++++++----------- 1 file changed, 162 insertions(+), 116 deletions(-) diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp index c209b0b070b1..26dfd0aef73c 100644 --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp @@ -11,12 +11,14 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -92,17 +94,77 @@ struct MaliC55FrameInfo { class MaliC55CameraData : public Camera::Private { public: - MaliC55CameraData(PipelineHandler *pipe, MediaEntity *entity) - : Camera::Private(pipe), entity_(entity) + struct Tpg { + std::vector sizes(unsigned int mbusCode) const; + + Size resolution_; + std::unique_ptr sd_; + }; + + struct Inline { + std::unique_ptr csi2_; + std::unique_ptr sensor_; + }; + using CameraType = std::variant; + + MaliC55CameraData(PipelineHandler *pipe) + : Camera::Private(pipe) { } - int init(); int loadIPA(); - /* Deflect these functionalities to either TPG or CameraSensor. */ - std::vector sizes(unsigned int mbusCode) const; - Size resolution() const; + Tpg *initTpg(MediaEntity *entity); + Inline *initInline(MediaEntity *entity); + + std::vector sizes(unsigned int mbusCode) const + { + return std::visit(utils::overloaded{ + [&](const Tpg &tpg) -> std::vector { + return tpg.sizes(mbusCode); + }, + [&](const Inline &in) -> std::vector { + return in.sensor_->sizes(mbusCode); + } + }, input_); + } + + V4L2Subdevice *subdev() const + { + return std::visit(utils::overloaded{ + [&](const Tpg &tpg) -> V4L2Subdevice * { + return tpg.sd_.get(); + }, + [&](const Inline &in) -> V4L2Subdevice * { + return in.sensor_->device(); + }, + }, input_); + } + + CameraSensor *sensor() const + { + return std::visit(utils::overloaded{ + [&](auto &) -> CameraSensor * { + ASSERT(false); + return nullptr; + }, + [&](const Inline &in) -> CameraSensor * { + return in.sensor_.get(); + }, + }, input_); + } + + Size resolution() const + { + return std::visit(utils::overloaded{ + [&](const Tpg &tpg) -> Size { + return tpg.resolution_; + }, + [&](const Inline &in) -> Size { + return in.sensor_->resolution(); + }, + }, input_); + } int pixfmtToMbusCode(const PixelFormat &pixFmt) const; const PixelFormat &bestRawFormat() const; @@ -112,11 +174,6 @@ public: PixelFormat adjustRawFormat(const PixelFormat &pixFmt) const; Size adjustRawSizes(const PixelFormat &pixFmt, const Size &rawSize) const; - std::unique_ptr sensor_; - - MediaEntity *entity_; - std::unique_ptr csi_; - std::unique_ptr sd_; Stream frStream_; Stream dsStream_; @@ -126,58 +183,28 @@ public: std::unique_ptr delayedCtrls_; + CameraType input_; + private: - void initTPGData(); void setSensorControls(const ControlList &sensorControls); - std::string id_; - Size tpgResolution_; }; -int MaliC55CameraData::init() +MaliC55CameraData::Tpg *MaliC55CameraData::initTpg(MediaEntity *entity) { - int ret; + Tpg tpg; - sd_ = std::make_unique(entity_); - ret = sd_->open(); + tpg.sd_ = std::make_unique(entity); + int ret = tpg.sd_->open(); if (ret) { - LOG(MaliC55, Error) << "Failed to open sensor subdevice"; - return ret; - } - - /* If this camera is created from TPG, we return here. */ - if (entity_->name() == "mali-c55 tpg") { - initTPGData(); - return 0; - } - - /* - * Register a CameraSensor if we connect to a sensor and create - * an entity for the connected CSI-2 receiver. - */ - sensor_ = CameraSensorFactoryBase::create(entity_); - if (!sensor_) - return -ENODEV; - - const MediaPad *sourcePad = entity_->getPadByIndex(0); - MediaEntity *csiEntity = sourcePad->links()[0]->sink()->entity(); - - csi_ = std::make_unique(csiEntity); - ret = csi_->open(); - if (ret) { - LOG(MaliC55, Error) << "Failed to open CSI-2 subdevice"; - return ret; + LOG(MaliC55, Error) << "Failed to open TPG subdevice"; + return nullptr; } - return 0; -} - -void MaliC55CameraData::initTPGData() -{ /* Replicate the CameraSensor implementation for TPG. */ - V4L2Subdevice::Formats formats = sd_->formats(0); + V4L2Subdevice::Formats formats = tpg.sd_->formats(0); if (formats.empty()) - return; + return nullptr; std::vector tpgSizes; @@ -187,19 +214,35 @@ void MaliC55CameraData::initTPGData() [](const SizeRange &range) { return range.max; }); } - tpgResolution_ = tpgSizes.back(); + tpg.resolution_ = tpgSizes.back(); + + return &input_.emplace(std::move(tpg)); } -void MaliC55CameraData::setSensorControls(const ControlList &sensorControls) +MaliC55CameraData::Inline *MaliC55CameraData::initInline(MediaEntity *sensor) { - delayedCtrls_->push(sensorControls); + Inline in; + + /* Register a CameraSensor and create an entity for the CSI-2 receiver. */ + in.sensor_ = CameraSensorFactoryBase::create(sensor); + if (!in.sensor_) + return nullptr; + + const MediaPad *sourcePad = sensor->getPadByIndex(0); + MediaEntity *csiEntity = sourcePad->links()[0]->sink()->entity(); + + in.csi2_ = std::make_unique(csiEntity); + int ret = in.csi2_->open(); + if (ret) { + LOG(MaliC55, Error) << "Failed to open CSI-2 subdevice"; + return nullptr; + } + + return &input_.emplace(std::move(in)); } -std::vector MaliC55CameraData::sizes(unsigned int mbusCode) const +std::vector MaliC55CameraData::Tpg::sizes(unsigned int mbusCode) const { - if (sensor_) - return sensor_->sizes(mbusCode); - V4L2Subdevice::Formats formats = sd_->formats(0); if (formats.empty()) return {}; @@ -218,12 +261,9 @@ std::vector MaliC55CameraData::sizes(unsigned int mbusCode) const return sizes; } -Size MaliC55CameraData::resolution() const +void MaliC55CameraData::setSensorControls(const ControlList &sensorControls) { - if (sensor_) - return sensor_->resolution(); - - return tpgResolution_; + delayedCtrls_->push(sensorControls); } /* @@ -242,7 +282,7 @@ int MaliC55CameraData::pixfmtToMbusCode(const PixelFormat &pixFmt) const if (!bayerFormat.isValid()) return -EINVAL; - V4L2Subdevice::Formats formats = sd_->formats(0); + V4L2Subdevice::Formats formats = subdev()->formats(0); unsigned int sensorMbusCode = 0; unsigned int bitDepth = 0; @@ -280,7 +320,7 @@ const PixelFormat &MaliC55CameraData::bestRawFormat() const { static const PixelFormat invalidPixFmt = {}; - for (const auto &fmt : sd_->formats(0)) { + for (const auto &fmt : subdev()->formats(0)) { BayerFormat sensorBayer = BayerFormat::fromMbusCode(fmt.first); if (!sensorBayer.isValid()) @@ -302,11 +342,11 @@ const PixelFormat &MaliC55CameraData::bestRawFormat() const void MaliC55CameraData::updateControls(const ControlInfoMap &ipaControls) { - if (!sensor_) + if (std::holds_alternative(input_)) return; IPACameraSensorInfo sensorInfo; - int ret = sensor_->sensorInfo(&sensorInfo); + int ret = sensor()->sensorInfo(&sensorInfo); if (ret) { LOG(MaliC55, Error) << "Failed to retrieve sensor info"; return; @@ -379,7 +419,7 @@ int MaliC55CameraData::loadIPA() int ret; /* Do not initialize IPA for TPG. */ - if (!sensor_) + if (std::holds_alternative(input_)) return 0; ipa_ = IPAManager::createIPA(pipe(), 1, 1); @@ -388,20 +428,20 @@ int MaliC55CameraData::loadIPA() ipa_->setSensorControls.connect(this, &MaliC55CameraData::setSensorControls); - std::string ipaTuningFile = ipa_->configurationFile(sensor_->model() + ".yaml", + std::string ipaTuningFile = ipa_->configurationFile(sensor()->model() + ".yaml", "uncalibrated.yaml"); /* We need to inform the IPA of the sensor configuration */ ipa::mali_c55::IPAConfigInfo ipaConfig{}; - ret = sensor_->sensorInfo(&ipaConfig.sensorInfo); + ret = sensor()->sensorInfo(&ipaConfig.sensorInfo); if (ret) return ret; - ipaConfig.sensorControls = sensor_->controls(); + ipaConfig.sensorControls = sensor()->controls(); ControlInfoMap ipaControls; - ret = ipa_->init({ ipaTuningFile, sensor_->model() }, ipaConfig, + ret = ipa_->init({ ipaTuningFile, sensor()->model() }, ipaConfig, &ipaControls); if (ret) { LOG(MaliC55, Error) << "Failed to initialise the Mali-C55 IPA"; @@ -444,13 +484,13 @@ CameraConfiguration::Status MaliC55CameraConfiguration::validate() * The TPG doesn't support flips, so we only need to calculate a * transform if we have a sensor. */ - if (data_->sensor_) { + if (std::holds_alternative(data_->input_)) { + combinedTransform_ = Transform::Rot0; + } else { Orientation requestedOrientation = orientation; - combinedTransform_ = data_->sensor_->computeTransform(&orientation); + combinedTransform_ = data_->sensor()->computeTransform(&orientation); if (orientation != requestedOrientation) status = Adjusted; - } else { - combinedTransform_ = Transform::Rot0; } /* Only 2 streams available. */ @@ -927,39 +967,44 @@ int PipelineHandlerMaliC55::configure(Camera *camera, /* Link the graph depending if we are operating the TPG or a sensor. */ MaliC55CameraData *data = cameraData(camera); - if (data->csi_) { - const MediaEntity *csiEntity = data->csi_->entity(); - ret = csiEntity->getPadByIndex(1)->links()[0]->setEnabled(true); - } else { - ret = data->entity_->getPadByIndex(0)->links()[0]->setEnabled(true); - } + ret = std::visit(utils::overloaded{ + [](MaliC55CameraData::Tpg &tpg) { + const MediaEntity *tpgEntity = tpg.sd_->entity(); + return tpgEntity->getPadByIndex(0)->links()[0]->setEnabled(true); + }, + [](MaliC55CameraData::Inline &in) { + const MediaEntity *csi2Entity = in.csi2_->entity(); + return csi2Entity->getPadByIndex(1)->links()[0]->setEnabled(true); + }, + }, data->input_); if (ret) return ret; MaliC55CameraConfiguration *maliConfig = static_cast(config); V4L2SubdeviceFormat subdevFormat = maliConfig->sensorFormat_; - ret = data->sd_->getFormat(0, &subdevFormat); + + /* Apply format to the origin of the pipeline and propagate it. */ + ret = std::visit(utils::overloaded{ + [&](MaliC55CameraData::Tpg &tpg) { + return tpg.sd_->setFormat(0, &subdevFormat); + }, + [&](MaliC55CameraData::Inline &in) { + int r = in.sensor_->setFormat(&subdevFormat, + maliConfig->combinedTransform()); + if (r) + return r; + + r = in.csi2_->setFormat(0, &subdevFormat); + if (r) + return r; + + return in.csi2_->getFormat(1, &subdevFormat); + }, + }, data->input_); if (ret) return ret; - if (data->sensor_) { - ret = data->sensor_->setFormat(&subdevFormat, - maliConfig->combinedTransform()); - if (ret) - return ret; - } - - if (data->csi_) { - ret = data->csi_->setFormat(0, &subdevFormat); - if (ret) - return ret; - - ret = data->csi_->getFormat(1, &subdevFormat); - if (ret) - return ret; - } - V4L2DeviceFormat statsFormat; ret = stats_->getFormat(&statsFormat); if (ret) @@ -973,8 +1018,6 @@ int PipelineHandlerMaliC55::configure(Camera *camera, /* * Propagate the format to the ISP sink pad and configure the input * crop rectangle (no crop at the moment). - * - * \todo Configure the CSI-2 receiver. */ ret = isp_->setFormat(0, &subdevFormat); if (ret) @@ -1058,18 +1101,18 @@ int PipelineHandlerMaliC55::configure(Camera *camera, /* We need to inform the IPA of the sensor configuration */ ipa::mali_c55::IPAConfigInfo ipaConfig{}; - ret = data->sensor_->sensorInfo(&ipaConfig.sensorInfo); + ret = data->sensor()->sensorInfo(&ipaConfig.sensorInfo); if (ret) return ret; - ipaConfig.sensorControls = data->sensor_->controls(); + ipaConfig.sensorControls = data->sensor()->controls(); /* * And we also need to tell the IPA the bayerOrder of the data (as * affected by any flips that we've configured) */ const Transform &combinedTransform = maliConfig->combinedTransform(); - BayerFormat::Order bayerOrder = data->sensor_->bayerOrder(combinedTransform); + BayerFormat::Order bayerOrder = data->sensor()->bayerOrder(combinedTransform); ControlInfoMap ipaControls; ret = data->ipa_->configure(ipaConfig, utils::to_underlying(bayerOrder), @@ -1283,7 +1326,7 @@ void PipelineHandlerMaliC55::applyScalerCrop(Camera *camera, if (!scalerCrop) return; - if (!data->sensor_) { + if (std::holds_alternative(data->input_)) { LOG(MaliC55, Error) << "ScalerCrop not supported for TPG"; return; } @@ -1291,7 +1334,7 @@ void PipelineHandlerMaliC55::applyScalerCrop(Camera *camera, Rectangle nativeCrop = *scalerCrop; IPACameraSensorInfo sensorInfo; - int ret = data->sensor_->sensorInfo(&sensorInfo); + int ret = data->sensor()->sensorInfo(&sensorInfo); if (ret) { LOG(MaliC55, Error) << "Failed to retrieve sensor info"; return; @@ -1573,9 +1616,9 @@ bool PipelineHandlerMaliC55::registerTPGCamera(MediaLink *link) } std::unique_ptr data = - std::make_unique(this, link->source()->entity()); + std::make_unique(this); - if (data->init()) + if (!data->initTpg(link->source()->entity())) return false; return registerMaliCamera(std::move(data), name); @@ -1600,21 +1643,24 @@ bool PipelineHandlerMaliC55::registerSensorCamera(MediaLink *ispLink) continue; std::unique_ptr data = - std::make_unique(this, sensor); - if (data->init()) + std::make_unique(this); + + auto *in = data->initInline(sensor); + if (!in) return false; - data->properties_ = data->sensor_->properties(); + data->properties_ = in->sensor_->properties(); - const CameraSensorProperties::SensorDelays &delays = data->sensor_->sensorDelays(); + const CameraSensorProperties::SensorDelays &delays = + in->sensor_->sensorDelays(); std::unordered_map params = { { V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } }, { V4L2_CID_EXPOSURE, { delays.exposureDelay, false } }, }; - data->delayedCtrls_ = - std::make_unique(data->sensor_->device(), - params); + V4L2Subdevice *sensorSubdev = in->sensor_->device(); + data->delayedCtrls_ = std::make_unique(sensorSubdev, + params); isp_->frameStart.connect(data->delayedCtrls_.get(), &DelayedControls::applyControls); From patchwork Tue Mar 31 16:36:32 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 26394 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 0FFCEC32F5 for ; Tue, 31 Mar 2026 16:36:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C29FF62D47; Tue, 31 Mar 2026 18:36:56 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="cT+lA0o/"; 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 1C20A6274D for ; Tue, 31 Mar 2026 18:36:51 +0200 (CEST) Received: from [100.93.44.16] (net-93-65-100-155.cust.vodafonedsl.it [93.65.100.155]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A03E220FF; Tue, 31 Mar 2026 18:35:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1774974928; bh=8GJoWmvnnhVfjvW8kFKHhENpJe9siUMg4bcn9jHEZB8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=cT+lA0o/n1Bjjl4XPJBNZzd9QbzM7xC2gGmF+f8g8GoF38y5UNTSItb2RqRe4aAp+ KnUfqMBK/E67iIkOD2lyWa2avfflHhgXxy5vrmpw86rQ0jzbOdk48d6xifa0XJt8BS gPvyD8LTVaZq8Q4nXcbTxFvfmg2YIwY7274h184U= From: Jacopo Mondi Date: Tue, 31 Mar 2026 18:36:32 +0200 Subject: [PATCH v7 4/8] libcamera: mali-c55: Register memory input camera MIME-Version: 1.0 Message-Id: <20260331-mali-cru-v7-4-4caedc898a0e@ideasonboard.com> References: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> In-Reply-To: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> To: Daniel Scally , libcamera-devel@lists.libcamera.org Cc: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Jacopo Mondi X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=9956; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=8GJoWmvnnhVfjvW8kFKHhENpJe9siUMg4bcn9jHEZB8=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBpy/ggHj3UYFjvlAckWdos+4/3LYKJBidU06VLC Frw4Nj6yXiJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCacv4IAAKCRByNAaPFqFW PO+PD/96I3CaFnkRUwd5Vzu78AcorK15ffwi7DZrpDxsS1qMTBtV74iZjSWS7w8tUzYfLUEwFlY twOa8evwB+XaeJfi0BHOEMA9T06kmdf6sEOdnNXLvKg2EsOL0+DSdDBx3YM+G3qa3vavZkK8flQ pHhOutVhaNj3c6s1NkJw/uF3Ae5W/urGQP4SoHvU4nyG6pMF+phfQS6rPXlvJCu3rN2G4/28xpN sFkW0stON0r+Jcps3XLp/QF1UlB5AJ7gOt3FTG+lOdtT/aubZ7Ioxx2cz9RTHnPBUIMY8521gOX Cgt13bIBunNgwoEbOUXbfnIoyg3etjz96ZZShTHGcqoHP/LSY0EC85Y9J6oq4WiabwKdBi28Vqn +py3qDCHUrSq17FSHvbuA8oTjJyW+8yvlFs8YLJUbkpH8yidXy3LKKgxyld0Y8v4mFCvtaWS12j r1hDU0rINixEnBETkMYvV1BAt2ESIuchHA1h2eokmEzWWW73QQZj3LMMLpzDW7AnOgdnaMPEeXo MQd807RS5NHfaHPcMqUyOZ680TiA505UB8RJ4eJkfUHscKdW3uMrPwk25iguzytpJBC+fSfkvxh DkRVRCCne4veST44WAseKmzpnrBZJARqfYUMgUke6dPaXWkYdhtFYAl5j0urWV+1hhYLbJbWg6A JwX3WyH8t3U3x5w== 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" Add support to Mali C55 pipeline handler for memory-to-memory camera mode. The Mali-C55, as integrated in the Renesas RZ/V2H(P) SoC, is fed with images saved to memory by the CRU unit and read on behalf of the ISP by the IVC. Update the pipeline handler's match() function to search for the CRU media entity necessary to register a memory input camera. Create and initialize a CameraData instance for the memory camera use case if a valid CRU is found and initialize the IVC components used to feed the ISP with images read from memory. Do not implement camera configuration for the time being to reuce the patch size. It will be provided in the following patches. Signed-off-by: Daniel Scally Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/mali-c55/mali-c55.cpp | 154 +++++++++++++++++++++++---- 1 file changed, 136 insertions(+), 18 deletions(-) diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp index 26dfd0aef73c..d17b026db119 100644 --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp @@ -44,6 +44,8 @@ #include "libcamera/internal/v4l2_subdevice.h" #include "libcamera/internal/v4l2_videodevice.h" +#include "rzg2l-cru.h" + namespace { bool isFormatRaw(const libcamera::PixelFormat &pixFmt) @@ -105,7 +107,12 @@ public: std::unique_ptr csi2_; std::unique_ptr sensor_; }; - using CameraType = std::variant; + + struct Memory { + std::unique_ptr cru_; + }; + + using CameraType = std::variant; MaliC55CameraData(PipelineHandler *pipe) : Camera::Private(pipe) @@ -116,6 +123,7 @@ public: Tpg *initTpg(MediaEntity *entity); Inline *initInline(MediaEntity *entity); + Memory *initMemory(MediaDevice *cruMedia); std::vector sizes(unsigned int mbusCode) const { @@ -125,7 +133,10 @@ public: }, [&](const Inline &in) -> std::vector { return in.sensor_->sizes(mbusCode); - } + }, + [&](const Memory &mem) -> std::vector { + return mem.cru_->sizes(); + }, }, input_); } @@ -138,6 +149,9 @@ public: [&](const Inline &in) -> V4L2Subdevice * { return in.sensor_->device(); }, + [&](const Memory &mem) -> V4L2Subdevice * { + return mem.cru_->sensor()->device(); + }, }, input_); } @@ -151,6 +165,9 @@ public: [&](const Inline &in) -> CameraSensor * { return in.sensor_.get(); }, + [&](const Memory &mem) -> CameraSensor * { + return mem.cru_->sensor(); + }, }, input_); } @@ -163,6 +180,9 @@ public: [&](const Inline &in) -> Size { return in.sensor_->resolution(); }, + [&](const Memory &mem) -> Size { + return mem.cru_->resolution(); + }, }, input_); } @@ -241,6 +261,19 @@ MaliC55CameraData::Inline *MaliC55CameraData::initInline(MediaEntity *sensor) return &input_.emplace(std::move(in)); } +MaliC55CameraData::Memory *MaliC55CameraData::initMemory(MediaDevice *cruMedia) +{ + Memory mem; + + mem.cru_ = std::make_unique(); + + int ret = mem.cru_->init(cruMedia); + if (ret) + return nullptr; + + return &input_.emplace(std::move(mem)); +} + std::vector MaliC55CameraData::Tpg::sizes(unsigned int mbusCode) const { V4L2Subdevice::Formats formats = sd_->formats(0); @@ -721,11 +754,15 @@ private: const std::string &name); bool registerTPGCamera(MediaLink *link); bool registerSensorCamera(MediaLink *link); + bool registerMemoryInputCamera(MediaLink *link); std::shared_ptr media_; + std::shared_ptr cruMedia_; std::unique_ptr isp_; std::unique_ptr stats_; std::unique_ptr params_; + std::unique_ptr ivcSd_; + std::unique_ptr ivc_; std::vector> statsBuffers_; std::queue availableStatsBuffers_; @@ -976,6 +1013,9 @@ int PipelineHandlerMaliC55::configure(Camera *camera, const MediaEntity *csi2Entity = in.csi2_->entity(); return csi2Entity->getPadByIndex(1)->links()[0]->setEnabled(true); }, + [](MaliC55CameraData::Memory &) { + return 0; + }, }, data->input_); if (ret) return ret; @@ -1001,6 +1041,9 @@ int PipelineHandlerMaliC55::configure(Camera *camera, return in.csi2_->getFormat(1, &subdevFormat); }, + [](MaliC55CameraData::Memory &) { + return 0; + }, }, data->input_); if (ret) return ret; @@ -1673,6 +1716,66 @@ bool PipelineHandlerMaliC55::registerSensorCamera(MediaLink *ispLink) return true; } +bool PipelineHandlerMaliC55::registerMemoryInputCamera(MediaLink *link) +{ + /* + * Errors are not fatal at this point, return true and just skip + * registering a camera for this media link. + */ + const std::string &name = link->source()->entity()->name(); + if (name != "rzv2h ivc block") { + LOG(MaliC55, Warning) << "Unsupported direct connection to " + << link->source()->entity()->name(); + return true; + } + + if (!cruMedia_) { + LOG(MaliC55, Warning) << "Unable to find CRU for memory input"; + return true; + } + + /* + * From now on, errors should be reported up as we have the components + * we need to support memory-to-memory and if we fail something has + * to be fixed. + */ + + ivcSd_ = V4L2Subdevice::fromEntityName(media_.get(), + "rzv2h ivc block"); + if (!ivcSd_ || ivcSd_->open() < 0) + return false; + + ivc_ = V4L2VideoDevice::fromEntityName(media_.get(), + "rzv2h-ivc"); + if (!ivc_ || ivc_->open() < 0) + return false; + + std::unique_ptr data = + std::make_unique(this); + + auto *mem = data->initMemory(cruMedia_.get()); + if (!mem) + return false; + + CameraSensor *sensor = data->sensor(); + data->properties_ = sensor->properties(); + + const CameraSensorProperties::SensorDelays &delays = sensor->sensorDelays(); + std::unordered_map params = { + { V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } }, + { V4L2_CID_EXPOSURE, { delays.exposureDelay, false } }, + }; + + data->delayedCtrls_ = + std::make_unique(sensor->device(), params); + isp_->frameStart.connect(data->delayedCtrls_.get(), + &DelayedControls::applyControls); + + ivc_->bufferReady.connect(mem->cru_.get(), &RZG2LCRU::returnBuffer); + + return registerMaliCamera(std::move(data), sensor->device()->entity()->name()); +} + bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator) { const MediaPad *ispSink; @@ -1682,14 +1785,14 @@ bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator) * The TPG and the downscale pipe are both optional blocks and may not * be fitted. */ - DeviceMatch dm("mali-c55"); - dm.add("mali-c55 isp"); - dm.add("mali-c55 resizer fr"); - dm.add("mali-c55 fr"); - dm.add("mali-c55 3a stats"); - dm.add("mali-c55 3a params"); - - media_ = acquireMediaDevice(enumerator, dm); + DeviceMatch c55Dm("mali-c55"); + c55Dm.add("mali-c55 isp"); + c55Dm.add("mali-c55 resizer fr"); + c55Dm.add("mali-c55 fr"); + c55Dm.add("mali-c55 3a stats"); + c55Dm.add("mali-c55 3a params"); + + media_ = acquireMediaDevice(enumerator, c55Dm); if (!media_) return false; @@ -1749,6 +1852,25 @@ bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator) stats_->bufferReady.connect(this, &PipelineHandlerMaliC55::statsBufferReady); params_->bufferReady.connect(this, &PipelineHandlerMaliC55::paramsBufferReady); + /* + * We also need to search for the rzg2l-cru CSI-2 receiver. If we find + * that then we need to work in memory input mode instead of the inline + * mode. The absence of this match is not necessarily a failure at this + * point...it depends on the media links that we investigate momentarily. + * + * This is a bit hacky, because there could be multiple of these media + * devices and we're just taking the first. We need modular pipelines to + * properly solve the issue. + */ + static const std::regex cruCsi2Regex("csi-[0-9a-f]{8}.csi2"); + static const std::regex cruIpRegex("cru-ip-[0-9a-f]{8}.cru[0-9]"); + + DeviceMatch cruDm("rzg2l_cru"); + cruDm.add(cruCsi2Regex); + cruDm.add(cruIpRegex); + cruDm.add("CRU output"); + cruMedia_ = acquireMediaDevice(enumerator, cruDm); + ispSink = isp_->entity()->getPadByIndex(0); if (!ispSink || ispSink->links().empty()) { LOG(MaliC55, Error) << "ISP sink pad error"; @@ -1762,13 +1884,6 @@ bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator) * MEDIA_ENT_F_CAM_SENSOR - The test pattern generator * MEDIA_ENT_F_VID_IF_BRIDGE - A CSI-2 receiver * MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER - An input device - * - * The last one will be unsupported for now. The TPG is relatively easy, - * we just register a Camera for it. If we have a CSI-2 receiver we need - * to check its sink pad and register Cameras for anything connected to - * it (probably...there are some complex situations in which that might - * not be true but let's pretend they don't exist until we come across - * them) */ bool registered; for (MediaLink *link : ispSink->links()) { @@ -1788,7 +1903,10 @@ bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator) break; case MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER: - LOG(MaliC55, Warning) << "Memory input not yet supported"; + registered = registerMemoryInputCamera(link); + if (!registered) + return registered; + break; default: LOG(MaliC55, Error) << "Unsupported entity function"; From patchwork Tue Mar 31 16:36:33 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 26395 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 A3694BDCBD for ; Tue, 31 Mar 2026 16:36:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 25F6262D24; Tue, 31 Mar 2026 18:36:58 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="qV4nIkNT"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 66C0962D1B for ; Tue, 31 Mar 2026 18:36:51 +0200 (CEST) Received: from [100.93.44.16] (net-93-65-100-155.cust.vodafonedsl.it [93.65.100.155]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id F092531A9; Tue, 31 Mar 2026 18:35:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1774974929; bh=TM7VmBjE8vfgc8t0dcQuhc3P87EZAMjVVw3CwS12mcg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=qV4nIkNT42fQqMx9h1GVd9SpfU8u9iS2tv2DkEQ7VCkuNAxQoEAfBKIwvroO0YEFe ayvaFx1zef3CmLiPbCCM/pvueR9oIFQc6W8/cPoZSdq5y5yRD1hj7nJtcp0Hg02Vpr u8vrG84LdpHds9Jx54wOJZ6HRZQbnEBmPWmnCvcU= From: Jacopo Mondi Date: Tue, 31 Mar 2026 18:36:33 +0200 Subject: [PATCH v7 5/8] libcamera: mali-c55: Configure camera in memory-to-memory MIME-Version: 1.0 Message-Id: <20260331-mali-cru-v7-5-4caedc898a0e@ideasonboard.com> References: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> In-Reply-To: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> To: Daniel Scally , libcamera-devel@lists.libcamera.org Cc: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Jacopo Mondi X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=1848; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=TM7VmBjE8vfgc8t0dcQuhc3P87EZAMjVVw3CwS12mcg=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBpy/ggn3zRzq+6TnbudW0ifgAJGRTrEeaQWoo1p L2uj54TU+KJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCacv4IAAKCRByNAaPFqFW PFzSD/0cLGX1NZB9YSvpRrBLWD7zy4s2nkT9ZWvVv+5DAUHrjHtz1mKbjSpnCniLxJ4hZeO4/JN MdK9m/rVEfbp+1GqWpp5GTfIr2lQLWkztiqaEga7sEWbyyuI5tOLBePyh+BphP8LVQ74y/Lzv0w Cs8aAzlRqoTMuwSJ7VYYB1yB/z5K6bC0vX2duunqX0+Uq6wo7nmDn653PNoD4CcemziYj9BZQN6 P8KlgAxgF9HdNdvC35xMKAsEYOS6fDXzqDhw9/YwLyEgb2np7lGUOCB/Chf9J4qCocX2PxmCTEJ gu/5lUq3jAkReMeVTMvdoua+ljum/xeY1U508EiYFKpXM3fTQD+Ou0HtCfdB4tIlf2H6xtK0Ex3 Bv9kUjNpnoNSIQTEjsTn7GjvQXKS6jhV+ltZ7LHSe+dT2kr5lpNsJ3cjv+S9RuV16UQ2O6Y1YuP BjpbVuMgurLCORAD3E7nuRqySEP2FxXc9S1BpMskNvZnbDjW+mLscyhogg13bm8Mp2SYx6DCEhI PhKlhUxfljhYnzUtju1BKrL1RzCWJakj4voVEo7hfJyVV6oYoJBiOSPDvyxRS+N+Lh9p3EItcTj 7oJPvw1lVcUsq0jYk74NeVcZoaIkIzYuKQpmkyHnJT5ALTLNo7G5uCVX7cNk0yAtAjsuLhOvC07 Rq5/xP3u2g67PiQ== 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" Add support for memory-to-memory Camera to the PipelineHandlerMaliC55::configure() function. Start by enabling the IVC links, then configure the CRU and propagate the format to the IVC. Signed-off-by: Jacopo Mondi Reviewed-by: Barnabás Pőcze --- src/libcamera/pipeline/mali-c55/mali-c55.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp index d17b026db119..566fa0549675 100644 --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp @@ -1013,8 +1013,9 @@ int PipelineHandlerMaliC55::configure(Camera *camera, const MediaEntity *csi2Entity = in.csi2_->entity(); return csi2Entity->getPadByIndex(1)->links()[0]->setEnabled(true); }, - [](MaliC55CameraData::Memory &) { - return 0; + [&](MaliC55CameraData::Memory &) { + const MediaEntity *ivcEntity = ivcSd_->entity(); + return ivcEntity->getPadByIndex(1)->links()[0]->setEnabled(true); }, }, data->input_); if (ret) @@ -1041,8 +1042,23 @@ int PipelineHandlerMaliC55::configure(Camera *camera, return in.csi2_->getFormat(1, &subdevFormat); }, - [](MaliC55CameraData::Memory &) { - return 0; + [&](MaliC55CameraData::Memory &mem) { + V4L2DeviceFormat inputFormat; + + int r = mem.cru_->configure(&subdevFormat, &inputFormat); + if (r) + return r; + + /* Propagate the CRU format to the IVC input. */ + r = ivcSd_->setFormat(0, &subdevFormat); + if (r) + return r; + + r = ivcSd_->getFormat(1, &subdevFormat); + if (r) + return r; + + return ivc_->setFormat(&inputFormat); }, }, data->input_); if (ret) From patchwork Tue Mar 31 16:36:34 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 26396 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 26860C32F6 for ; Tue, 31 Mar 2026 16:37:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AF14362D1E; Tue, 31 Mar 2026 18:36:58 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="fBjiKtJv"; 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 C704E62D22 for ; Tue, 31 Mar 2026 18:36:51 +0200 (CEST) Received: from [100.93.44.16] (net-93-65-100-155.cust.vodafonedsl.it [93.65.100.155]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 496912451; Tue, 31 Mar 2026 18:35:29 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1774974929; bh=t/458MfNw43ZCbnpnbloRwKiZfi2yr4wEtFyXhslYiE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=fBjiKtJvyMFsR+lcP6irGpSVl7+vLwluN9nqlCBCHK/A6n880quOorFo121mCIIVa jRFVCg71ndZ5cHHKdcJ2jcRTVO9J4D950weTXokMs4SnilJMsEjnkOGqFtGS/9U5xg jCa4sxkx5laFQDB/yvLgRwrfP7UwCoD+TBpsxPyc= From: Jacopo Mondi Date: Tue, 31 Mar 2026 18:36:34 +0200 Subject: [PATCH v7 6/8] libcamera: mali-c55: Do not rely on bufferCount MIME-Version: 1.0 Message-Id: <20260331-mali-cru-v7-6-4caedc898a0e@ideasonboard.com> References: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> In-Reply-To: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> To: Daniel Scally , libcamera-devel@lists.libcamera.org Cc: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Jacopo Mondi X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=2194; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=t/458MfNw43ZCbnpnbloRwKiZfi2yr4wEtFyXhslYiE=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBpy/ggskkAOY1Dw14XQ4F3ZxLM4C1pIf6MN8iMw QwSfLJX6MyJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCacv4IAAKCRByNAaPFqFW PDWVD/4vnW8QFFwzPPVUg8akvB/BW2QizhPvHsFf+RSQ9n1wwokaylcx8Ou7M2PyYQQGUmd6ovC r18byXqpo9ADdgZdb3QA34xCp8+V9kGn8R++5D0/7nkDB5w8Dm+HiwmMP3fyCc3Rg+NGQwd2GWv 5fe0j0Dmha1yOZWaLtX5HpiWHTH2w6jmRPvwMIWUiIu9ZTSwuO7ppzmll2X0IiT+FlBSrhMjBuk rH9XzEHhLJmj4kmFrFZqAZ5JrZlr7JRqHf9cV55bdR3nxwOJTUrjrW8LHcn6j9dfjYXG2f9Ju7j AsRnB+YvfLUjeCfRGzHyMtLTy58xiYG8Pes8f6+sx89qhBEh5RJcppubYuikPPef2PQsdbv66NM sR2mFn5LMh10MddV4E8m17mP3GM94AKjviOz/BiB1vNVQtGhUCYGrYoR5kTy96bY5qAFiYka3PP ZXzGWnk0YCBIAJ9/5hRFDNUKY/xD4316TtU2WP/ElEYzTGsZWCLbvJjMJ/r2TSpr0xUeJvh4NEZ zdDPQ8haosSH/QFwAWNBu+3k7tUU5oJ+cTqvUa1HfhnbKcmIyyxQbRqwwD2TeB+r+XuAmLlscFh p4VstnqM71gxQzv0hmB4lsQOq/la1z8sOUySvpQgOm8Jn/qMHC7AyhL47Jobz6/+Uy32Gfn1y+t V5THrVz+lg4uJLQ== 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" Do not rely on bufferCount for the allocation of parameters and stats buffers but add instead kMaliC55BufferCount which is also used to limit the number of in-flight requests supported by the pipeline handler. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/mali-c55/mali-c55.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp index 566fa0549675..ce1f0b65cd6e 100644 --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp @@ -48,6 +48,8 @@ namespace { +static constexpr unsigned int kMaliC55BufferCount = 16; + bool isFormatRaw(const libcamera::PixelFormat &pixFmt) { return libcamera::PixelFormatInfo::info(pixFmt).colourEncoding == @@ -778,7 +780,7 @@ private: }; PipelineHandlerMaliC55::PipelineHandlerMaliC55(CameraManager *manager) - : PipelineHandler(manager), dsFitted_(true) + : PipelineHandler(manager, kMaliC55BufferCount), dsFitted_(true) { } @@ -1227,14 +1229,8 @@ int PipelineHandlerMaliC55::allocateBuffers(Camera *camera) { MaliC55CameraData *data = cameraData(camera); unsigned int ipaBufferId = 1; - unsigned int bufferCount; int ret; - bufferCount = std::max({ - data->frStream_.configuration().bufferCount, - data->dsStream_.configuration().bufferCount, - }); - auto pushBuffers = [&](const std::vector> &buffers, std::queue &queue, std::vector &ipaBuffers) { @@ -1249,14 +1245,14 @@ int PipelineHandlerMaliC55::allocateBuffers(Camera *camera) } }; - ret = stats_->allocateBuffers(bufferCount, &statsBuffers_); + ret = stats_->allocateBuffers(kMaliC55BufferCount, &statsBuffers_); if (ret < 0) return ret; pushBuffers(statsBuffers_, availableStatsBuffers_, data->ipaStatBuffers_); - ret = params_->allocateBuffers(bufferCount, ¶msBuffers_); + ret = params_->allocateBuffers(kMaliC55BufferCount, ¶msBuffers_); if (ret < 0) return ret; From patchwork Tue Mar 31 16:36:35 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 26397 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 90D42C32F7 for ; Tue, 31 Mar 2026 16:37:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4A54462D2C; Tue, 31 Mar 2026 18:36:59 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="hHgnP17D"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 31DE462D26 for ; Tue, 31 Mar 2026 18:36:52 +0200 (CEST) Received: from [100.93.44.16] (net-93-65-100-155.cust.vodafonedsl.it [93.65.100.155]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A27A825B5; Tue, 31 Mar 2026 18:35:29 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1774974929; bh=CzTYhqk8LUFjjiKF0NNAHl3BVN+64xBZR3KkW8s/LhE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=hHgnP17DHFPgHjuQ0L0sPui9NpRrPS2n+Ad6o+nh07Xg/vRzfaQkD4l7z4CR8QLUS XRqQ6curHJ5Pnkcc7ATr3A8RmESwgg8/81tSNf3K2nwYlFDsqsK9ZsZPSvtqZmh3Xm e0Lufk6UDHs4b9Yc8kWfMspFQSjsWwpowGsxNtrY= From: Jacopo Mondi Date: Tue, 31 Mar 2026 18:36:35 +0200 Subject: [PATCH v7 7/8] libcamera: mali-c55: Implement capture for memory-to-memory MIME-Version: 1.0 Message-Id: <20260331-mali-cru-v7-7-4caedc898a0e@ideasonboard.com> References: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> In-Reply-To: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> To: Daniel Scally , libcamera-devel@lists.libcamera.org Cc: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Jacopo Mondi X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=12755; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=CzTYhqk8LUFjjiKF0NNAHl3BVN+64xBZR3KkW8s/LhE=; b=kA0DAAoBcjQGjxahVjwByyZiAGnL+CHItFm5aPiZpl05SMS+611dcziVXOlKcTyNO8k8wEseM YkCMwQAAQoAHRYhBLXEPUiAmiCKj1g4wHI0Bo8WoVY8BQJpy/ghAAoJEHI0Bo8WoVY85poP/25v kUS905GnrgDSDfmGI3ILnuEDZ8PRwgvCqamj3n672wthm+UUYGHG2M0MjALJj8GThbYgEbg9vdB 1m2fWnGVV2veLbO1/83Sp18pR0TSbdxKfAHJSNPciALeNNCN5UG1YxNJcZD/BQ89ZVpnDlWSxvy EZ0CvOv+7H6XnXeh8Z17aw+HsYFOyTZ9dN8MF/VtT4mkAC1cwiOQ0+RJOqLe+2AhgEHaiLGYzAv DvrYipBJSfMguqITNsohavNnquv2TsMh5uc5cgpxMTKjvUpkAoM1PEUqEDVnJD40el/NQEWHPaI WXKEEI96d8lV/g37rJCtojWoUp9fitK3XTxtLKdAhfFMpfw8YgoA6BX88I7tTqW6I52W44J4uox PbbMPKvre/NqtmsXFzdVkBnk7n/WTiYHxfCdyAn7LCHx3RLvyd41n6Oy5dcOxCkrXW3VY7kph4i EBqo9nUId7yrLOOo8kORSyfecZtSLHQ++24s156jBlp3E29dCfldeWk3j4VFh9/i6n1Mt674gVf 7qJ+uDzPIDzUq56TMKjA8/tdhxKweaqheJOxTp0FXrSYMC9A5tKT8Q9AutgbHjsfcbS4t3D87qn PWm4/fFpB3yo61k7D78Fr9J9J6i7Y5Lj7uAnRucBDEK384SRvahGcD3IU1Li4jwQOqNX22OI0ph CTcxY 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" Plumb in the MaliC55 pipeline handler support for capturing frames from memory using the CRU. Introduce a data flow which uses the CRU to feed the ISP through the IVC. In detail: - push incoming request to a pending queue until a buffer from the CRU is available - delay the call to ipa_->fillParams() to the CRU buffer ready event - once the IPA has computed parameters feed the ISP through the IVC with buffers from the CRU, params and statistics - Handle completion of in-flight requests: in m2m mode buffers are queued earlier to the ISP capture devices. If the camera is stopped these buffers are returned earlier in error state: complete the Request bypassing the IPA operations - As cancelled Requests might now be completed earlier then IPA events, modify the IPA event handler to ignore Requests that have been completed already Signed-off-by: Daniel Scally Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/mali-c55/mali-c55.cpp | 211 ++++++++++++++++++++++----- 1 file changed, 174 insertions(+), 37 deletions(-) diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp index ce1f0b65cd6e..c3856f7c0a11 100644 --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -90,6 +91,7 @@ struct MaliC55FrameInfo { FrameBuffer *paramBuffer; FrameBuffer *statBuffer; + FrameBuffer *rawBuffer; bool paramsDone; bool statsDone; @@ -693,6 +695,7 @@ public: void imageBufferReady(FrameBuffer *buffer); void paramsBufferReady(FrameBuffer *buffer); void statsBufferReady(FrameBuffer *buffer); + void cruBufferReady(FrameBuffer *buffer); void paramsComputed(unsigned int requestId, uint32_t bytesused); void statsProcessed(unsigned int requestId, const ControlList &metadata); @@ -741,7 +744,7 @@ private: MaliC55FrameInfo *findFrameInfo(FrameBuffer *buffer); MaliC55FrameInfo *findFrameInfo(Request *request); - void tryComplete(MaliC55FrameInfo *info); + void tryComplete(MaliC55FrameInfo *info, bool cancelled = false); int configureRawStream(MaliC55CameraData *data, const StreamConfiguration &config, @@ -750,6 +753,9 @@ private: const StreamConfiguration &config, V4L2SubdeviceFormat &subdevFormat); + MaliC55FrameInfo *prepareFrameInfo(Request *request); + void queueRequestToCru(MaliC55CameraData *data, Request *request); + void applyScalerCrop(Camera *camera, const ControlList &controls); bool registerMaliCamera(std::unique_ptr data, @@ -1222,6 +1228,13 @@ void PipelineHandlerMaliC55::freeBuffers(Camera *camera) if (params_->releaseBuffers()) LOG(MaliC55, Error) << "Failed to release params buffers"; + if (auto *mem = std::get_if(&data->input_)) { + if (ivc_->releaseBuffers()) + LOG(MaliC55, Error) << "Failed to release input buffers"; + if (mem->cru_->freeBuffers()) + LOG(MaliC55, Error) << "Failed to release CRU buffers"; + } + return; } @@ -1245,6 +1258,12 @@ int PipelineHandlerMaliC55::allocateBuffers(Camera *camera) } }; + if (std::holds_alternative(data->input_)) { + ret = ivc_->importBuffers(kMaliC55BufferCount); + if (ret < 0) + return ret; + } + ret = stats_->allocateBuffers(kMaliC55BufferCount, &statsBuffers_); if (ret < 0) return ret; @@ -1276,6 +1295,24 @@ int PipelineHandlerMaliC55::start(Camera *camera, [[maybe_unused]] const Control if (ret) return ret; + if (auto *mem = std::get_if(&data->input_)) { + ret = mem->cru_->start(kMaliC55BufferCount); + if (ret) { + LOG(MaliC55, Error) + << "Failed to start CRU " << camera->id(); + freeBuffers(camera); + return ret; + } + + ret = ivc_->streamOn(); + if (ret) { + LOG(MaliC55, Error) + << "Failed to start IVC" << camera->id(); + freeBuffers(camera); + return ret; + } + } + if (data->ipa_) { ret = data->ipa_->start(); if (ret) { @@ -1357,6 +1394,11 @@ void PipelineHandlerMaliC55::stopDevice(Camera *camera) isp_->setFrameStartEnabled(false); + if (auto *mem = std::get_if(&data->input_)) { + ivc_->streamOff(); + mem->cru_->stop(); + } + for (MaliC55Pipe &pipe : pipes_) { if (!pipe.stream) continue; @@ -1468,10 +1510,67 @@ void PipelineHandlerMaliC55::applyScalerCrop(Camera *camera, } } +MaliC55FrameInfo *PipelineHandlerMaliC55::prepareFrameInfo(Request *request) +{ + if (availableStatsBuffers_.empty()) { + LOG(MaliC55, Error) << "Stats buffer underrun"; + return nullptr; + } + + if (availableParamsBuffers_.empty()) { + LOG(MaliC55, Error) << "Params buffer underrun"; + return nullptr; + } + + MaliC55FrameInfo &frameInfo = frameInfoMap_[request->sequence()]; + frameInfo.request = request; + frameInfo.statBuffer = availableStatsBuffers_.front(); + availableStatsBuffers_.pop(); + frameInfo.paramBuffer = availableParamsBuffers_.front(); + availableParamsBuffers_.pop(); + + frameInfo.paramsDone = false; + frameInfo.statsDone = false; + + return &frameInfo; +} + +void PipelineHandlerMaliC55::queueRequestToCru(MaliC55CameraData *data, + Request *request) +{ + auto *mem = std::get_if(&data->input_); + ASSERT(mem); + + FrameBuffer *cruBuffer = mem->cru_->queueBuffer(request); + ASSERT(cruBuffer); + + auto frameInfo = prepareFrameInfo(request); + ASSERT(frameInfo); + frameInfo->rawBuffer = cruBuffer; + + for (auto &[stream, buffer] : request->buffers()) { + MaliC55Pipe *pipe = pipeFromStream(data, stream); + + pipe->cap->queueBuffer(buffer); + } + + data->ipa_->queueRequest(request->sequence(), request->controls()); +} + int PipelineHandlerMaliC55::queueRequestDevice(Camera *camera, Request *request) { MaliC55CameraData *data = cameraData(camera); + /* + * If we're in memory input mode, we need to queue the Request to the + * CRU, otherwise we can just do everything immediately. + */ + if (std::holds_alternative(data->input_)) { + queueRequestToCru(data, request); + + return 0; + } + /* Do not run the IPA if the TPG is in use. */ if (!data->ipa_) { MaliC55FrameInfo frameInfo; @@ -1492,32 +1591,13 @@ int PipelineHandlerMaliC55::queueRequestDevice(Camera *camera, Request *request) return 0; } - if (availableStatsBuffers_.empty()) { - LOG(MaliC55, Error) << "Stats buffer underrun"; + auto frameInfo = prepareFrameInfo(request); + if (!frameInfo) return -ENOENT; - } - - if (availableParamsBuffers_.empty()) { - LOG(MaliC55, Error) << "Params buffer underrun"; - return -ENOENT; - } - - MaliC55FrameInfo frameInfo; - frameInfo.request = request; - - frameInfo.statBuffer = availableStatsBuffers_.front(); - availableStatsBuffers_.pop(); - frameInfo.paramBuffer = availableParamsBuffers_.front(); - availableParamsBuffers_.pop(); - - frameInfo.paramsDone = false; - frameInfo.statsDone = false; - - frameInfoMap_[request->sequence()] = frameInfo; data->ipa_->queueRequest(request->sequence(), request->controls()); data->ipa_->fillParams(request->sequence(), - frameInfo.paramBuffer->cookie()); + frameInfo->paramBuffer->cookie()); return 0; } @@ -1536,18 +1616,21 @@ MaliC55FrameInfo *PipelineHandlerMaliC55::findFrameInfo(FrameBuffer *buffer) { for (auto &[sequence, info] : frameInfoMap_) { if (info.paramBuffer == buffer || - info.statBuffer == buffer) + info.statBuffer == buffer || + info.rawBuffer == buffer) return &info; } return nullptr; } -void PipelineHandlerMaliC55::tryComplete(MaliC55FrameInfo *info) +void PipelineHandlerMaliC55::tryComplete(MaliC55FrameInfo *info, bool cancelled) { - if (!info->paramsDone) - return; - if (!info->statsDone) + /* + * If the buffer has been cancelled, we complete the request without + * waiting for the IPA. + */ + if (!cancelled && (!info->paramsDone || !info->statsDone)) return; Request *request = info->request; @@ -1571,13 +1654,15 @@ void PipelineHandlerMaliC55::imageBufferReady(FrameBuffer *buffer) ASSERT(info); if (completeBuffer(request, buffer)) - tryComplete(info); + tryComplete(info, + buffer->metadata().status == FrameMetadata::FrameCancelled); } void PipelineHandlerMaliC55::paramsBufferReady(FrameBuffer *buffer) { MaliC55FrameInfo *info = findFrameInfo(buffer); - ASSERT(info); + if (!info) + return; info->paramsDone = true; @@ -1587,7 +1672,8 @@ void PipelineHandlerMaliC55::paramsBufferReady(FrameBuffer *buffer) void PipelineHandlerMaliC55::statsBufferReady(FrameBuffer *buffer) { MaliC55FrameInfo *info = findFrameInfo(buffer); - ASSERT(info); + if (!info) + return; Request *request = info->request; MaliC55CameraData *data = cameraData(request->_d()->camera()); @@ -1598,32 +1684,80 @@ void PipelineHandlerMaliC55::statsBufferReady(FrameBuffer *buffer) sensorControls); } +void PipelineHandlerMaliC55::cruBufferReady(FrameBuffer *buffer) +{ + /* + * If the buffer has been cancelled, do not ask the IPA to prepare + * parameters. + * + * The Request this cancelled buffer belongs to will be handled by + * imageBufferReady() as we have queued buffers to the ISP capture + * devices at the same time we have queued this buffer to the CRU + * when running in m2m mode. + */ + if (buffer->metadata().status == FrameMetadata::FrameCancelled) + return; + + MaliC55FrameInfo *info = findFrameInfo(buffer); + ASSERT(info); + + Request *request = info->request; + request->_d()->metadata().set(controls::SensorTimestamp, + buffer->metadata().timestamp); + + /* Ought we do something with the sensor's controls here...? */ + MaliC55CameraData *data = cameraData(request->_d()->camera()); + data->ipa_->fillParams(request->sequence(), info->paramBuffer->cookie()); +} + void PipelineHandlerMaliC55::paramsComputed(unsigned int requestId, uint32_t bytesused) { - MaliC55FrameInfo &frameInfo = frameInfoMap_[requestId]; + auto it = frameInfoMap_.find(requestId); + if (it == frameInfoMap_.end()) + return; + + MaliC55FrameInfo &frameInfo = it->second; Request *request = frameInfo.request; + if (!request) + return; + MaliC55CameraData *data = cameraData(request->_d()->camera()); /* * Queue buffers for stats and params, then queue buffers to the capture - * video devices. + * video devices if we're running in Inline mode or with the TPG. + * + * If we're running in M2M buffers have been queued to the capture + * devices at queueRequestToCru() time and here we only have to queue + * buffers to the IVC input to start a transfer. */ frameInfo.paramBuffer->_d()->metadata().planes()[0].bytesused = bytesused; params_->queueBuffer(frameInfo.paramBuffer); stats_->queueBuffer(frameInfo.statBuffer); - for (auto &[stream, buffer] : request->buffers()) { - MaliC55Pipe *pipe = pipeFromStream(data, stream); + if (!std::holds_alternative(data->input_)) { + for (auto &[stream, buffer] : request->buffers()) { + MaliC55Pipe *pipe = pipeFromStream(data, stream); - pipe->cap->queueBuffer(buffer); + pipe->cap->queueBuffer(buffer); + } + } else { + ivc_->queueBuffer(frameInfo.rawBuffer); + frameInfo.rawBuffer = nullptr; } } void PipelineHandlerMaliC55::statsProcessed(unsigned int requestId, const ControlList &metadata) { - MaliC55FrameInfo &frameInfo = frameInfoMap_[requestId]; + auto it = frameInfoMap_.find(requestId); + if (it == frameInfoMap_.end()) + return; + + MaliC55FrameInfo &frameInfo = it->second; + if (!frameInfo.request) + return; frameInfo.statsDone = true; frameInfo.request->_d()->metadata().merge(metadata); @@ -1785,6 +1919,9 @@ bool PipelineHandlerMaliC55::registerMemoryInputCamera(MediaLink *link) ivc_->bufferReady.connect(mem->cru_.get(), &RZG2LCRU::returnBuffer); + V4L2VideoDevice *cruOutput = mem->cru_->output(); + cruOutput->bufferReady.connect(this, &PipelineHandlerMaliC55::cruBufferReady); + return registerMaliCamera(std::move(data), sensor->device()->entity()->name()); } From patchwork Tue Mar 31 16:36:36 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 26398 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 17531C32F8 for ; Tue, 31 Mar 2026 16:37:01 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0C4D762D45; Tue, 31 Mar 2026 18:37:00 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="uPc3k8BP"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6BCE862D28 for ; Tue, 31 Mar 2026 18:36:52 +0200 (CEST) Received: from [100.93.44.16] (net-93-65-100-155.cust.vodafonedsl.it [93.65.100.155]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id F0C2B20FF; Tue, 31 Mar 2026 18:35:29 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1774974930; bh=KJL2CcIY5VX/RCnpQMI88gQPmVI3D0wCVe1eWSxWWGU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=uPc3k8BP9C7g8J3Xav5ZyKzn2LT981wSkdkbuH/ibOMqMyqcsNTBcxQgOXaikkAWm mvk333fT//giMXnv7HHjHJgRd9Hvr2Z+r4sETKnL2uQFCSBd4LOEG+ziaMdPzn6M12 JT1sLehhrIzuRoo2nqe7ZbPeuPaeqaYF6BBML3hk= From: Jacopo Mondi Date: Tue, 31 Mar 2026 18:36:36 +0200 Subject: [PATCH v7 8/8] libcamera: mali-c55: Fix sensor size computation MIME-Version: 1.0 Message-Id: <20260331-mali-cru-v7-8-4caedc898a0e@ideasonboard.com> References: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> In-Reply-To: <20260331-mali-cru-v7-0-4caedc898a0e@ideasonboard.com> To: Daniel Scally , libcamera-devel@lists.libcamera.org Cc: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Jacopo Mondi X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=1117; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=KJL2CcIY5VX/RCnpQMI88gQPmVI3D0wCVe1eWSxWWGU=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBpy/ghF8ruG/QF+yIvRiZWI/Vca/YkENSuWl9pM L/y6U4XDrSJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCacv4IQAKCRByNAaPFqFW PKIWD/9EdF1XIH9Y8E1Lst0fSJI0ezYG6R15ppet5gjolFuhL2KHmC9V0DdCN/7Ax6pbmsiQegI qU7slqTvy8Pab88riWGUb28rg5GSfXjyHccQ7Xe40rfR6sdK/8FTK6pSGajzpNlr6Eid/CHq5ag ybAcdHBuuX7o7EQbzzHzcKAXZitPab+7mjMRYaatOyqKALqPxS8LFvbLv8dRRSJ7O+JTlVBxI9w 7JKK1JH9vdKON7Vkh7Mo05YbCqxiHLxxlDFA2gAchS3SHLggdRVIc3/oIlBPHd3lwaeqas5YixY tgIkcrU5Mh303CVD87YKexKdAJ+53WwdCNqcOXIIdJZTg4l7hNFRzJnbzOEojdYeHuLKovf7ATJ 1LQNxWp3aQ3H3pPEIc1gLXLalkc5l+7KC2Yged/TxawDrqyj/LgVosSPyjJQ3u7WVGsFsN5LQg8 MSG3EslQTCmzwdmmr95lM79Ad9yTOFQ6FJmSSArUqJXQevdD80FjFyVwn1y56PwkBqyM++wVDIS vqzDQpMlUb+eNz6x3wFSXW8EPkcRW18V1ukiY/K9bF/emywoeAJaxybj9EgAFvq+nG4GC+hekdy 4JAw43ZlYrre/tvl3nx3gbjijz/rQqfX4IYLoU/mA3JHLBOjtxuysGIHZMEGSuvKvuIE7L6Fl4C h5AQbjjVtlqtdwA== 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 last size in the list is always selected unconditionally because the current best distance is not updated properly during the search. Fix the size computation procedure which has an inverted assignment. Signed-off-by: Jacopo Mondi Reviewed-by: Daniel Scally Tested-by: Daniel Scally Reviewed-by: Barnabás Pőcze --- src/libcamera/pipeline/mali-c55/mali-c55.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp index c3856f7c0a11..3d502855dede 100644 --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp @@ -662,7 +662,7 @@ CameraConfiguration::Status MaliC55CameraConfiguration::validate() std::abs(static_cast(minSensorSize.height) - static_cast(size.height)); if (dist < distance) { - dist = distance; + distance = dist; bestSize = size; } }