From patchwork Mon Nov 22 12:34:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 14682 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 12E89BF415 for ; Mon, 22 Nov 2021 12:34:37 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8357D6038A; Mon, 22 Nov 2021 13:34:35 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="brUUvbf+"; dkim-atps=neutral Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6222E60230 for ; Mon, 22 Nov 2021 13:34:33 +0100 (CET) Received: by mail-wr1-x42e.google.com with SMTP id u18so32434854wrg.5 for ; Mon, 22 Nov 2021 04:34:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ZfpMXzbl3q5XsQMWg0BIa1Ijw3X2uxtGb5zZvcNBtDk=; b=brUUvbf+Az/3yypkXBp+I0s+gqsT/ciklj/TF4IrRIyFSaeE4MXCSRTLtih44p8d2o gXUp7UqfIsECBLabLXDSB/5RU/U/KwFzXipIVBq5PvOTi/ZiSxKt2UtHpS/fIkuziPIB ypWG0+3LJzGXk/IHal+6a61LvVCCDa3fTzqUFXRpzEAanhKb/kmPuqWvbYLn2bijknIc Sd3TwW/qwIQR4LZXbB5nvSy0LVa66121dJbMju18XS0uidJhd+QLnh6tu+qs9DLmkZwp vDZ7b8m78QsQZDvnUH7l5h03Lxbxn2tEnfCbOyJH+lieSQhZ1dPvEH5oy92S7rHUlOq7 GeKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ZfpMXzbl3q5XsQMWg0BIa1Ijw3X2uxtGb5zZvcNBtDk=; b=7hG08NhrdrrH31DMvoq/PIqWDhYTfZ6JRmhbVEAEa/z3faSgUvfT/lLid5k4LKdpD2 TEAWe+XjHH3MUraqDFOW27sc2zEv5tyNHO3yZ+UTblkdsJsnOaulZJACRl09QpYcbyr3 auAiFBiQ8Qt+SnW4FuVWgzQqOWtEENOBl2zKBT1o8kjhjfw9zYpJvn+q0/ZdJ429VCI5 JtZGueG8dfm5Y0MvrPT3tvAXyVpObjsFr3keEToXdOUddsW0S4kE/V9ssSzmcNmotgRf ULqg8JyIJYU3l9ZoWdMBUovz8+7H7M7lnAL2vMWNj05XA36z6kOSKitW6+Qd99zN+ISW NOvQ== X-Gm-Message-State: AOAM532nJBL+6qu3tScE8j/RTlC3HDQ1PXZuZFOI8a7D/brUkE+OGV5D c1B87ALRUhItGb3r1dBkbrT1VJcjoOUcwNzS X-Google-Smtp-Source: ABdhPJwBqXp6hzA6Q7paT5cMA4kW1vIT3eVZdd0JnjI5zCcjGb0PAalWzWIY9+VTOQ7WrjCGPqaU0g== X-Received: by 2002:a5d:628f:: with SMTP id k15mr38232826wru.363.1637584472925; Mon, 22 Nov 2021 04:34:32 -0800 (PST) Received: from naush-laptop.pitowers.org ([2a00:1098:3142:14:eb05:dcc9:77a0:2542]) by smtp.gmail.com with ESMTPSA id h7sm8482231wrt.64.2021.11.22.04.34.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Nov 2021 04:34:32 -0800 (PST) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Date: Mon, 22 Nov 2021 12:34:26 +0000 Message-Id: <20211122123427.808484-2-naush@raspberrypi.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211122123427.808484-1-naush@raspberrypi.com> References: <20211122123427.808484-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 1/2] pipeline: raspberrypi: Split out device enumeration and camera registration 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" Split out PipelineHandlerRPi::match() so that media device enumeration and acquisition is separated from camera registration. The former logic remains in PipelineHandlerRPi::match(), whereas the latter logic is moved into a new PipelineHandlerRPi::registerCameras() member function. Signed-off-by: Naushir Patuck Reviewed-by: Laurent Pinchart --- src/libcamera/pipeline/raspberrypi/raspberrypi.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp index 4f6c699a4379..9aa7e9eef5e7 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -311,6 +311,7 @@ private: return static_cast(camera->_d()); } + bool registerCameras(); int queueAllBuffers(Camera *camera); int prepareBuffers(Camera *camera); void freeBuffers(Camera *camera); @@ -1010,6 +1011,11 @@ bool PipelineHandlerRPi::match(DeviceEnumerator *enumerator) if (!isp_) return false; + return registerCameras(); +} + +bool PipelineHandlerRPi::registerCameras() +{ std::unique_ptr data = std::make_unique(this); if (!data->dmaHeap_.isValid()) return false; From patchwork Mon Nov 22 12:34:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 14683 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 E38F9C324F for ; Mon, 22 Nov 2021 12:34:37 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7393C60394; Mon, 22 Nov 2021 13:34:37 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="jwlM1CNF"; dkim-atps=neutral Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 247936033C for ; Mon, 22 Nov 2021 13:34:34 +0100 (CET) Received: by mail-wr1-x42c.google.com with SMTP id n29so32355005wra.11 for ; Mon, 22 Nov 2021 04:34:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=SzHLwUjZud8JGLrthbyJvqLPt1vhtBbowMVa1Z2XZqs=; b=jwlM1CNFPO63j8MsRTjU1+Pj0jOns6Eom52TjD6njSHeWEbQdPALsiYF3h2rbG3R0A IMWuRkNWz/Amj//DjYh5duNnHJjdqfm3iunvW0PSakCL4Cc+FJ3+ace5OJxCohwf7vmN bEs5u04anaRAyqLaW2Q/wV5FZStg+CD6fOwh2WL/67mUN3XASmnbaOplSBsimAHn+RRt a8rNCetL72rS8QMpVZY+7nTEPYbuTsBFm4uVFFmCZqMlIPJgGaUinmGa8wdB0+93C2kw oSBRHWZxoNB0fqtGB09aXNJz2aoxo5IfD0BYFZWQOCZn6hNmQA4jcp69uLgUKXSpvh33 PQBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=SzHLwUjZud8JGLrthbyJvqLPt1vhtBbowMVa1Z2XZqs=; b=FN1Gh7I7FPjxogzrwdeZgajT2p8sBA6VSIeEl630iHcJk+BTps4A4AmfVijzsY4i3j bK7t5U91I/84VVQFtPindbzc15QzZU1KpMGfr0WXOfgeUOVJn75Q33uUZrzA1nMFf9Q3 c7APVAMGs5QHi2rr72InfEdgLxjSsUj2xwRzKMl4uRNWHdiK2VOabtPhtt8l/ul+068v Q5nkd91zl4ZvAbsToAVJOrmm5tTMepo7kfBUiPBpCriTpermJ5MPOoPlHN37Kw1nwqz4 kIi7D2qd9QD/9ZpU9Yx3T2zYgwwcnc6JnDvcM1jmLnpSk2OZy8zXR+JtVHGRqGzN+Pml QXlQ== X-Gm-Message-State: AOAM531dZoe3H50qBgPPHDckxCid6Pp5tcCgha/0/s85muHsXS28csxN G4HS4LgsbFU6y/2QYYQsTJfcOtP3DNpbYnbT X-Google-Smtp-Source: ABdhPJz7BSm8BuGpeWWnsECACFC8R3tqR3a4Z4jKEetpqzb4q3+Crva7wu9H+N28PEGx7gI6u7tVLw== X-Received: by 2002:a5d:6d8b:: with SMTP id l11mr16776085wrs.232.1637584473597; Mon, 22 Nov 2021 04:34:33 -0800 (PST) Received: from naush-laptop.pitowers.org ([2a00:1098:3142:14:eb05:dcc9:77a0:2542]) by smtp.gmail.com with ESMTPSA id h7sm8482231wrt.64.2021.11.22.04.34.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Nov 2021 04:34:33 -0800 (PST) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Date: Mon, 22 Nov 2021 12:34:27 +0000 Message-Id: <20211122123427.808484-3-naush@raspberrypi.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211122123427.808484-1-naush@raspberrypi.com> References: <20211122123427.808484-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 2/2] pipeline: raspberrypi: Allow registration of multiple cameras 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" Expand the pipeline handler camera registration to correctly handle multiple cameras attached to the platform. For example, Raspberry Pi Compute Module platforms have two camera connectors, and this change would allow the user to select either of the two cameras to run. There are associated kernel driver changes for both Unicam and the ISP needed to correctly advertise multiple media devices and nodes for multi-camera usage: https://github.com/raspberrypi/linux/pull/4140 https://github.com/raspberrypi/linux/pull/4709 However, this change is backward compatible with kernel builds that do not have these changes for standard single camera usage. Signed-off-by: Naushir Patuck --- .../pipeline/raspberrypi/raspberrypi.cpp | 113 ++++++++++++------ 1 file changed, 74 insertions(+), 39 deletions(-) diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp index 9aa7e9eef5e7..3f9e15514ed9 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -311,14 +311,11 @@ private: return static_cast(camera->_d()); } - bool registerCameras(); + int registerCameras(MediaDevice *unicam, MediaDevice *isp, const std::string &deviceId); int queueAllBuffers(Camera *camera); int prepareBuffers(Camera *camera); void freeBuffers(Camera *camera); void mapBuffers(Camera *camera, const RPi::BufferMap &buffers, unsigned int mask); - - MediaDevice *unicam_; - MediaDevice *isp_; }; RPiCameraConfiguration::RPiCameraConfiguration(const RPiCameraData *data) @@ -509,7 +506,7 @@ CameraConfiguration::Status RPiCameraConfiguration::validate() } PipelineHandlerRPi::PipelineHandlerRPi(CameraManager *manager) - : PipelineHandler(manager), unicam_(nullptr), isp_(nullptr) + : PipelineHandler(manager) { } @@ -993,49 +990,85 @@ int PipelineHandlerRPi::queueRequestDevice(Camera *camera, Request *request) bool PipelineHandlerRPi::match(DeviceEnumerator *enumerator) { - DeviceMatch unicam("unicam"); - DeviceMatch isp("bcm2835-isp"); + MediaDevice *unicamDevice, *ispDevice; + std::string deviceId; - unicam.add("unicam-image"); + /* + * String of indexes to append to the entity names when searching for + * the Unican media devices. The first string is empty (un-indexed) to + * to maintain backward compatability with old versions of the Unicam + * kernel driver that did not advertise instance indexes. + */ + for (const std::string &id : { "", "0", "1" }) { + DeviceMatch unicam("unicam"); + unicam.add("unicam" + id + "-image"); + unicamDevice = acquireMediaDevice(enumerator, unicam); - isp.add("bcm2835-isp0-output0"); /* Input */ - isp.add("bcm2835-isp0-capture1"); /* Output 0 */ - isp.add("bcm2835-isp0-capture2"); /* Output 1 */ - isp.add("bcm2835-isp0-capture3"); /* Stats */ + if (unicamDevice) { + deviceId = id == "1" ? "1" : "0"; + break; + } + } - unicam_ = acquireMediaDevice(enumerator, unicam); - if (!unicam_) + if (!unicamDevice) { + LOG(RPI, Debug) << "Unable to acquire a Unicam instance"; return false; + } - isp_ = acquireMediaDevice(enumerator, isp); - if (!isp_) + DeviceMatch isp("bcm2835-isp"); + isp.add("bcm2835-isp" + deviceId + "-output0"); /* Input */ + isp.add("bcm2835-isp" + deviceId + "-capture1"); /* Output 0 */ + isp.add("bcm2835-isp" + deviceId + "-capture2"); /* Output 1 */ + isp.add("bcm2835-isp" + deviceId + "-capture3"); /* Stats */ + ispDevice = acquireMediaDevice(enumerator, isp); + + if (!ispDevice) { + LOG(RPI, Error) << "Unable to acquire ISP instance " << deviceId; return false; + } + + int ret = registerCameras(unicamDevice, ispDevice, deviceId); + if (ret) { + LOG(RPI, Error) << "Failed to register camera: " << ret; + return false; + } - return registerCameras(); + return true; } -bool PipelineHandlerRPi::registerCameras() +int PipelineHandlerRPi::registerCameras(MediaDevice *unicam, MediaDevice *isp, + const std::string &deviceId) { std::unique_ptr data = std::make_unique(this); + if (!data->dmaHeap_.isValid()) - return false; + return -ENOMEM; + + MediaEntity *unicamImage = unicam->getEntityByName("unicam" + deviceId + "-image"); + MediaEntity *ispOutput0 = isp->getEntityByName("bcm2835-isp" + deviceId + "-output0"); + MediaEntity *ispCapture1 = isp->getEntityByName("bcm2835-isp" + deviceId + "-capture1"); + MediaEntity *ispCapture2 = isp->getEntityByName("bcm2835-isp" + deviceId + "-capture2"); + MediaEntity *ispCapture3 = isp->getEntityByName("bcm2835-isp" + deviceId + "-capture3"); + + if (!unicamImage || !ispOutput0 || !ispCapture1 || !ispCapture2 || !ispCapture3) + return -ENOENT; /* Locate and open the unicam video streams. */ - data->unicam_[Unicam::Image] = RPi::Stream("Unicam Image", unicam_->getEntityByName("unicam-image")); + data->unicam_[Unicam::Image] = RPi::Stream("Unicam Image", unicamImage); /* An embedded data node will not be present if the sensor does not support it. */ - MediaEntity *embeddedEntity = unicam_->getEntityByName("unicam-embedded"); - if (embeddedEntity) { - data->unicam_[Unicam::Embedded] = RPi::Stream("Unicam Embedded", embeddedEntity); + MediaEntity *unicamEmbedded = unicam->getEntityByName("unicam" + deviceId + "-embedded"); + if (unicamEmbedded) { + data->unicam_[Unicam::Embedded] = RPi::Stream("Unicam Embedded", unicamEmbedded); data->unicam_[Unicam::Embedded].dev()->bufferReady.connect(data.get(), &RPiCameraData::unicamBufferDequeue); } /* Tag the ISP input stream as an import stream. */ - data->isp_[Isp::Input] = RPi::Stream("ISP Input", isp_->getEntityByName("bcm2835-isp0-output0"), true); - data->isp_[Isp::Output0] = RPi::Stream("ISP Output0", isp_->getEntityByName("bcm2835-isp0-capture1")); - data->isp_[Isp::Output1] = RPi::Stream("ISP Output1", isp_->getEntityByName("bcm2835-isp0-capture2")); - data->isp_[Isp::Stats] = RPi::Stream("ISP Stats", isp_->getEntityByName("bcm2835-isp0-capture3")); + data->isp_[Isp::Input] = RPi::Stream("ISP Input", ispOutput0, true); + data->isp_[Isp::Output0] = RPi::Stream("ISP Output0", ispCapture1); + data->isp_[Isp::Output1] = RPi::Stream("ISP Output1", ispCapture2); + data->isp_[Isp::Stats] = RPi::Stream("ISP Stats", ispCapture3); /* Wire up all the buffer connections. */ data->unicam_[Unicam::Image].dev()->frameStart.connect(data.get(), &RPiCameraData::frameStarted); @@ -1046,7 +1079,7 @@ bool PipelineHandlerRPi::registerCameras() data->isp_[Isp::Stats].dev()->bufferReady.connect(data.get(), &RPiCameraData::ispOutputDequeue); /* Identify the sensor. */ - for (MediaEntity *entity : unicam_->entities()) { + for (MediaEntity *entity : unicam->entities()) { if (entity->function() == MEDIA_ENT_F_CAM_SENSOR) { data->sensor_ = std::make_unique(entity); break; @@ -1054,23 +1087,23 @@ bool PipelineHandlerRPi::registerCameras() } if (!data->sensor_) - return false; + return -EINVAL; if (data->sensor_->init()) - return false; + return -EINVAL; data->sensorFormats_ = populateSensorFormats(data->sensor_); ipa::RPi::SensorConfig sensorConfig; if (data->loadIPA(&sensorConfig)) { LOG(RPI, Error) << "Failed to load a suitable IPA library"; - return false; + return -EINVAL; } - if (sensorConfig.sensorMetadata ^ !!embeddedEntity) { + if (sensorConfig.sensorMetadata ^ !!unicamEmbedded) { LOG(RPI, Warning) << "Mismatch between Unicam and CamHelper for embedded data usage!"; sensorConfig.sensorMetadata = false; - if (embeddedEntity) + if (unicamEmbedded) data->unicam_[Unicam::Embedded].dev()->bufferReady.disconnect(); } @@ -1091,12 +1124,12 @@ bool PipelineHandlerRPi::registerCameras() for (auto stream : data->streams_) { if (stream->dev()->open()) - return false; + continue; } if (!data->unicam_[Unicam::Image].dev()->caps().hasMediaController()) { LOG(RPI, Error) << "Unicam driver does not use the MediaController, please update your kernel!"; - return false; + return -EINVAL; } /* @@ -1158,7 +1191,7 @@ bool PipelineHandlerRPi::registerCameras() if (!bayerFormat.isValid()) { LOG(RPI, Error) << "No Bayer format found"; - return false; + return -EINVAL; } data->nativeBayerOrder_ = bayerFormat.order; @@ -1173,12 +1206,14 @@ bool PipelineHandlerRPi::registerCameras() streams.insert(&data->isp_[Isp::Output1]); /* Create and register the camera. */ - const std::string &id = data->sensor_->id(); + const std::string &cameraId = data->sensor_->id(); std::shared_ptr camera = - Camera::create(std::move(data), id, streams); + Camera::create(std::move(data), cameraId, streams); registerCamera(std::move(camera)); - return true; + LOG(RPI, Info) << "Registered camera " << cameraId + << " to instance \"" << deviceId << "\""; + return 0; } int PipelineHandlerRPi::queueAllBuffers(Camera *camera)