From patchwork Thu Feb 28 20:04:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 679 Return-Path: Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 271B1610BA for ; Thu, 28 Feb 2019 21:03:47 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id A24CCE0006; Thu, 28 Feb 2019 20:03:46 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Feb 2019 21:04:01 +0100 Message-Id: <20190228200410.3022-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190228200410.3022-1-jacopo@jmondi.org> References: <20190228200410.3022-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 01/10] libcamera: ipu3: Group CIO2 devices X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Feb 2019 20:03:47 -0000 Group CIO2 devices (cio2, csi2 and image sensor) in a structure associated with the CameraData, to ease management of the CIO2 devices. Update the IPU3 pipeline handler implementation to avoid name clashes and break-out IPU3CameraData from the pipeline handler class for clarity. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 251 ++++++++++++++------------- 1 file changed, 133 insertions(+), 118 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 9694d0ce51ab..d3f1d9a95f81 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -24,6 +24,30 @@ namespace libcamera { LOG_DEFINE_CATEGORY(IPU3) +struct Cio2Device { + Cio2Device() + : output(nullptr), csi2(nullptr), sensor(nullptr) {} + + ~Cio2Device() + { + delete output; + delete csi2; + delete sensor; + } + + V4L2Device *output; + V4L2Subdevice *csi2; + V4L2Subdevice *sensor; +}; + +class IPU3CameraData : public CameraData +{ +public: + Cio2Device cio2; + + Stream stream_; +}; + class PipelineHandlerIPU3 : public PipelineHandler { public: @@ -47,65 +71,47 @@ public: bool match(DeviceEnumerator *enumerator); private: - class IPU3CameraData : public CameraData - { - public: - IPU3CameraData() - : cio2_(nullptr), csi2_(nullptr), sensor_(nullptr) {} - - ~IPU3CameraData() - { - delete cio2_; - delete csi2_; - delete sensor_; - } - - V4L2Device *cio2_; - V4L2Subdevice *csi2_; - V4L2Subdevice *sensor_; - - Stream stream_; - }; - IPU3CameraData *cameraData(const Camera *camera) { return static_cast( PipelineHandler::cameraData(camera)); } + int initCio2(unsigned int index, Cio2Device *cio2); void registerCameras(); - std::shared_ptr cio2_; - std::shared_ptr imgu_; + std::shared_ptr cio2MediaDev_; + std::shared_ptr imguMediaDev_; }; PipelineHandlerIPU3::PipelineHandlerIPU3(CameraManager *manager) - : PipelineHandler(manager), cio2_(nullptr), imgu_(nullptr) + : PipelineHandler(manager), cio2MediaDev_(nullptr), imguMediaDev_(nullptr) { } PipelineHandlerIPU3::~PipelineHandlerIPU3() { - if (cio2_) - cio2_->release(); + if (cio2MediaDev_) + cio2MediaDev_->release(); - if (imgu_) - imgu_->release(); + if (imguMediaDev_) + imguMediaDev_->release(); } std::map PipelineHandlerIPU3::streamConfiguration(Camera *camera, std::vector &streams) { - IPU3CameraData *data = cameraData(camera); std::map configs; + IPU3CameraData *data = cameraData(camera); + V4L2Subdevice *sensor = data->cio2.sensor; V4L2SubdeviceFormat format = {}; /* * FIXME: As of now, return the image format reported by the sensor. * In future good defaults should be provided for each stream. */ - if (data->sensor_->getFormat(0, &format)) { + if (sensor->getFormat(0, &format)) { LOG(IPU3, Error) << "Failed to create stream configurations"; return configs; } @@ -126,9 +132,9 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, { IPU3CameraData *data = cameraData(camera); StreamConfiguration *cfg = &config[&data->stream_]; - V4L2Subdevice *sensor = data->sensor_; - V4L2Subdevice *csi2 = data->csi2_; - V4L2Device *cio2 = data->cio2_; + V4L2Subdevice *sensor = data->cio2.sensor; + V4L2Subdevice *csi2 = data->cio2.csi2; + V4L2Device *cio2 = data->cio2.output; V4L2SubdeviceFormat subdevFormat = {}; V4L2DeviceFormat devFormat = {}; int ret; @@ -185,13 +191,14 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) { - IPU3CameraData *data = cameraData(camera); const StreamConfiguration &cfg = stream->configuration(); + IPU3CameraData *data = cameraData(camera); + V4L2Device *cio2 = data->cio2.output; if (!cfg.bufferCount) return -EINVAL; - int ret = data->cio2_->exportBuffers(&stream->bufferPool()); + int ret = cio2->exportBuffers(&stream->bufferPool()); if (ret) { LOG(IPU3, Error) << "Failed to request memory"; return ret; @@ -203,8 +210,9 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) { IPU3CameraData *data = cameraData(camera); + V4L2Device *cio2 = data->cio2.output; - int ret = data->cio2_->releaseBuffers(); + int ret = cio2->releaseBuffers(); if (ret) { LOG(IPU3, Error) << "Failed to release memory"; return ret; @@ -216,9 +224,10 @@ int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) int PipelineHandlerIPU3::start(const Camera *camera) { IPU3CameraData *data = cameraData(camera); + V4L2Device *cio2 = data->cio2.output; int ret; - ret = data->cio2_->streamOn(); + ret = cio2->streamOn(); if (ret) { LOG(IPU3, Info) << "Failed to start camera " << camera->name(); return ret; @@ -230,14 +239,16 @@ int PipelineHandlerIPU3::start(const Camera *camera) void PipelineHandlerIPU3::stop(const Camera *camera) { IPU3CameraData *data = cameraData(camera); + V4L2Device *cio2 = data->cio2.output; - if (data->cio2_->streamOff()) + if (cio2->streamOff()) LOG(IPU3, Info) << "Failed to stop camera " << camera->name(); } int PipelineHandlerIPU3::queueRequest(const Camera *camera, Request *request) { IPU3CameraData *data = cameraData(camera); + V4L2Device *cio2 = data->cio2.output; Stream *stream = &data->stream_; Buffer *buffer = request->findBuffer(stream); @@ -247,7 +258,7 @@ int PipelineHandlerIPU3::queueRequest(const Camera *camera, Request *request) return -ENOENT; } - data->cio2_->queueBuffer(buffer); + cio2->queueBuffer(buffer); return 0; } @@ -278,20 +289,20 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) imgu_dm.add("ipu3-imgu 1 viewfinder"); imgu_dm.add("ipu3-imgu 1 3a stat"); - cio2_ = enumerator->search(cio2_dm); - if (!cio2_) + cio2MediaDev_ = enumerator->search(cio2_dm); + if (!cio2MediaDev_) return false; - imgu_ = enumerator->search(imgu_dm); - if (!imgu_) + imguMediaDev_ = enumerator->search(imgu_dm); + if (!imguMediaDev_) return false; /* * It is safe to acquire both media devices at this point as * DeviceEnumerator::search() skips the busy ones for us. */ - cio2_->acquire(); - imgu_->acquire(); + cio2MediaDev_->acquire(); + imguMediaDev_->acquire(); /* * Disable all links that are enabled by default on CIO2, as camera @@ -300,28 +311,90 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) * Close the CIO2 media device after, as links are enabled and should * not need to be changed after. */ - if (cio2_->open()) + if (cio2MediaDev_->open()) goto error_release_mdev; - if (cio2_->disableLinks()) + if (cio2MediaDev_->disableLinks()) goto error_close_cio2; registerCameras(); - cio2_->close(); + cio2MediaDev_->close(); return true; error_close_cio2: - cio2_->close(); + cio2MediaDev_->close(); error_release_mdev: - cio2_->release(); - imgu_->release(); + cio2MediaDev_->release(); + imguMediaDev_->release(); return false; } +int PipelineHandlerIPU3::initCio2(unsigned int index, Cio2Device *cio2) +{ + int ret; + + /* Verify a sensor subdevice is connected to this CIO2 instance. */ + std::string csi2Name = "ipu3-csi2 " + std::to_string(index); + MediaEntity *entity = cio2MediaDev_->getEntityByName(csi2Name); + if (!entity) { + LOG(IPU3, Error) + << "Failed to get entity '" << csi2Name << "'"; + return -ENODEV; + } + + const std::vector &pads = entity->pads(); + if (pads.empty()) + return -EINVAL; + + /* IPU3 CSI-2 receivers have a single sink pad at index 0. */ + MediaPad *sink = pads[0]; + const std::vector &links = sink->links(); + if (links.empty()) + return -EINVAL; + + MediaLink *link = links[0]; + MediaEntity *sensorEntity = link->source()->entity(); + if (sensorEntity->function() != MEDIA_ENT_F_CAM_SENSOR) + return -ENODEV; + + ret = link->setEnabled(true); + if (ret) + return ret; + + /* + * Now that we're sure a sensor subdevice is connected, create and open + * video devices and subdevices associated with this CIO2 unit. + */ + cio2->sensor = new V4L2Subdevice(sensorEntity); + ret = cio2->sensor->open(); + if (ret) + return ret; + + cio2->csi2 = new V4L2Subdevice(entity); + ret = cio2->csi2->open(); + if (ret) + return ret; + + std::string cio2Name = "ipu3-cio2 " + std::to_string(index); + entity = cio2MediaDev_->getEntityByName(cio2Name); + if (!entity) { + LOG(IPU3, Error) + << "Failed to get entity '" << cio2Name << "'"; + return -EINVAL; + } + + cio2->output = new V4L2Device(entity); + ret = cio2->output->open(); + if (ret) + return ret; + + return 0; +} + /* * Cameras are created associating an image sensor (represented by a * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four @@ -329,85 +402,27 @@ error_release_mdev: */ void PipelineHandlerIPU3::registerCameras() { + int ret; + /* * For each CSI-2 receiver on the IPU3, create a Camera if an * image sensor is connected to it. */ unsigned int numCameras = 0; for (unsigned int id = 0; id < 4; ++id) { - std::string csi2Name = "ipu3-csi2 " + std::to_string(id); - MediaEntity *csi2 = cio2_->getEntityByName(csi2Name); - int ret; - - /* - * This shall not happen, as the device enumerator matched - * all entities described in the cio2_dm DeviceMatch. - * - * As this check is basically free, better stay safe than sorry. - */ - if (!csi2) - continue; - - const std::vector &pads = csi2->pads(); - if (pads.empty()) - continue; - - /* IPU3 CSI-2 receivers have a single sink pad at index 0. */ - MediaPad *sink = pads[0]; - const std::vector &links = sink->links(); - if (links.empty()) - continue; - - /* - * Verify that the receiver is connected to a sensor, enable - * the media link between the two, and create a Camera with - * a unique name. - */ - MediaLink *link = links[0]; - MediaEntity *sensor = link->source()->entity(); - if (sensor->function() != MEDIA_ENT_F_CAM_SENSOR) - continue; - - if (link->setEnabled(true)) - continue; - - std::unique_ptr data = utils::make_unique(); - - std::string cameraName = sensor->name() + " " + std::to_string(id); + std::unique_ptr data = + utils::make_unique(); std::vector streams{ &data->stream_ }; - std::shared_ptr camera = Camera::create(this, cameraName, streams); - - /* - * Create and open video devices and subdevices associated with - * the camera. - * - * If any of these operations fails, the Camera instance won't - * be registered. The 'camera' shared pointer and the 'data' - * unique pointers go out of scope and delete the objects they - * manage. - */ - std::string cio2Name = "ipu3-cio2 " + std::to_string(id); - MediaEntity *cio2 = cio2_->getEntityByName(cio2Name); - if (!cio2) { - LOG(IPU3, Error) - << "Failed to get entity '" << cio2Name << "'"; - continue; - } - - data->cio2_ = new V4L2Device(cio2); - ret = data->cio2_->open(); - if (ret) - continue; + Cio2Device *cio2 = &data->cio2; - data->sensor_ = new V4L2Subdevice(sensor); - ret = data->sensor_->open(); + ret = initCio2(id, cio2); if (ret) continue; - data->csi2_ = new V4L2Subdevice(csi2); - ret = data->csi2_->open(); - if (ret) - continue; + std::string cameraName = cio2->sensor->deviceName() + " " + + std::to_string(id); + std::shared_ptr camera = + Camera::create(this, cameraName, streams); setCameraData(camera.get(), std::move(data)); registerCamera(std::move(camera)); From patchwork Thu Feb 28 20:04:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 680 Return-Path: Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B8E64610BA for ; Thu, 28 Feb 2019 21:03:47 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id 4FDC3E0005; Thu, 28 Feb 2019 20:03:47 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Feb 2019 21:04:02 +0100 Message-Id: <20190228200410.3022-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190228200410.3022-1-jacopo@jmondi.org> References: <20190228200410.3022-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 02/10] libcamera: ipu3: Get default image sizes from sensor X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Feb 2019 20:03:47 -0000 Inspect all image sizes provided by the sensor and select the biggest one to be returned as default stream configuration instead of returning the currently applied one. Hardcode the stream pixel format to the one produced by the CIO2 unit, to be changed to the one provided by the ImgU. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 44 ++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index d3f1d9a95f81..4f1ab72debf8 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -71,6 +71,8 @@ public: bool match(DeviceEnumerator *enumerator); private: + static constexpr unsigned int IPU3_BUF_NUM = 4; + IPU3CameraData *cameraData(const Camera *camera) { return static_cast( @@ -102,27 +104,45 @@ std::map PipelineHandlerIPU3::streamConfiguration(Camera *camera, std::vector &streams) { + std::map> formats; std::map configs; IPU3CameraData *data = cameraData(camera); V4L2Subdevice *sensor = data->cio2.sensor; - V4L2SubdeviceFormat format = {}; + StreamConfiguration *config = &configs[&data->stream_]; + + config->pixelFormat = V4L2_PIX_FMT_IPU3_SGRBG10; + config->bufferCount = IPU3_BUF_NUM; /* - * FIXME: As of now, return the image format reported by the sensor. - * In future good defaults should be provided for each stream. + * Use the largest image size the sensor provides or + * use a default one. */ - if (sensor->getFormat(0, &format)) { - LOG(IPU3, Error) << "Failed to create stream configurations"; - return configs; + formats = sensor->formats(0); + if (formats.empty()) { + config->width = 1920; + config->height = 1080; + LOG(IPU3, Info) + << "Use default stream sizes " << config->width + << "x" << config->height; } - StreamConfiguration config = {}; - config.width = format.width; - config.height = format.height; - config.pixelFormat = V4L2_PIX_FMT_IPU3_SGRBG10; - config.bufferCount = 4; + auto it = formats.begin(); + while (it != formats.end()) { + for (SizeRange &range : it->second) { + if (range.maxWidth <= config->width || + range.maxHeight <= config->height) + continue; + + config->width = range.maxWidth; + config->height = range.maxHeight; + } + + ++it; + } - configs[&data->stream_] = config; + LOG(IPU3, Info) << "Stream format set to = (" << config->width << "x" + << config->height << ") - 0x" << std::hex + << config->pixelFormat; return configs; } From patchwork Thu Feb 28 20:04:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 681 Return-Path: Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6BCAE610BF for ; Thu, 28 Feb 2019 21:03:48 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id DE1CDE0006; Thu, 28 Feb 2019 20:03:47 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Feb 2019 21:04:03 +0100 Message-Id: <20190228200410.3022-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190228200410.3022-1-jacopo@jmondi.org> References: <20190228200410.3022-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 03/10] libcamera: ipu3: Initialize and link ImgU devices X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Feb 2019 20:03:49 -0000 Create video devices and subdevices associated with an ImgU unit, and link the entities in the media graph to prepare the device for capture operations at stream configuration time. As we support a single stream at the moment, always select imgu0. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 219 +++++++++++++++++++++++++-- 1 file changed, 207 insertions(+), 12 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 4f1ab72debf8..9fa59c1bc97e 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -24,6 +24,28 @@ namespace libcamera { LOG_DEFINE_CATEGORY(IPU3) +struct ImguDevice { + ImguDevice() + : imgu(nullptr), input(nullptr), output(nullptr), + viewfinder(nullptr), stat(nullptr) {} + + ~ImguDevice() + { + delete imgu; + delete input; + delete output; + delete viewfinder; + delete stat; + } + + V4L2Subdevice *imgu; + V4L2Device *input; + V4L2Device *output; + V4L2Device *viewfinder; + V4L2Device *stat; + /* TODO: add param video device for 3A tuning */ +}; + struct Cio2Device { Cio2Device() : output(nullptr), csi2(nullptr), sensor(nullptr) {} @@ -44,6 +66,7 @@ class IPU3CameraData : public CameraData { public: Cio2Device cio2; + ImguDevice *imgu; Stream stream_; }; @@ -71,6 +94,10 @@ public: bool match(DeviceEnumerator *enumerator); private: + static constexpr unsigned int IMGU_PAD_INPUT = 0; + static constexpr unsigned int IMGU_PAD_OUTPUT = 2; + static constexpr unsigned int IMGU_PAD_VF = 3; + static constexpr unsigned int IMGU_PAD_STAT = 4; static constexpr unsigned int IPU3_BUF_NUM = 4; IPU3CameraData *cameraData(const Camera *camera) @@ -79,9 +106,17 @@ private: PipelineHandler::cameraData(camera)); } + int linkImgu(ImguDevice *imgu); + + V4L2Device *openDevice(MediaDevice *media, std::string &name); + V4L2Subdevice *openSubdevice(MediaDevice *media, std::string &name); + int initImgu(ImguDevice *imgu); int initCio2(unsigned int index, Cio2Device *cio2); void registerCameras(); + ImguDevice imgu0_; + ImguDevice imgu1_; + std::shared_ptr cio2MediaDev_; std::shared_ptr imguMediaDev_; }; @@ -159,6 +194,15 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, V4L2DeviceFormat devFormat = {}; int ret; + /* + * TODO: dynamically assign ImgU devices; as of now, with a single + * stream supported, always use 'imgu0'. + */ + data->imgu = &imgu0_; + ret = linkImgu(data->imgu); + if (ret) + return ret; + /* * FIXME: as of now, the format gets applied to the sensor and is * propagated along the pipeline. It should instead be applied on the @@ -334,17 +378,29 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) if (cio2MediaDev_->open()) goto error_release_mdev; + if (imguMediaDev_->open()) + goto error_close_mdev; + if (cio2MediaDev_->disableLinks()) - goto error_close_cio2; + goto error_close_mdev; + + if (initImgu(&imgu0_)) + goto error_close_mdev; + + if (initImgu(&imgu1_)) + goto error_close_mdev; + registerCameras(); cio2MediaDev_->close(); + imguMediaDev_->close(); return true; -error_close_cio2: +error_close_mdev: cio2MediaDev_->close(); + imguMediaDev_->close(); error_release_mdev: cio2MediaDev_->release(); @@ -353,6 +409,153 @@ error_release_mdev: return false; } +/* Link entities in the ImgU unit to prepare for capture operations. */ +int PipelineHandlerIPU3::linkImgu(ImguDevice *imguDevice) +{ + MediaLink *link; + int ret; + + unsigned int index = imguDevice == &imgu0_ ? 0 : 1; + std::string imguName = "ipu3-imgu " + std::to_string(index); + std::string inputName = imguName + " input"; + std::string outputName = imguName + " output"; + std::string viewfinderName = imguName + " viewfinder"; + std::string statName = imguName + " 3a stat"; + + ret = imguMediaDev_->open(); + if (ret) + return ret; + + ret = imguMediaDev_->disableLinks(); + if (ret) { + imguMediaDev_->close(); + return ret; + } + + /* Link entities to configure the IMGU unit for capture. */ + link = imguMediaDev_->link(inputName, 0, imguName, IMGU_PAD_INPUT); + if (!link) { + LOG(IPU3, Error) + << "Failed to get link '" << inputName << "':0 -> '" + << imguName << "':0"; + ret = -ENODEV; + goto error_close_mediadev; + } + link->setEnabled(true); + + link = imguMediaDev_->link(imguName, IMGU_PAD_OUTPUT, outputName, 0); + if (!link) { + LOG(IPU3, Error) + << "Failed to get link '" << imguName << "':2 -> '" + << outputName << "':0"; + ret = -ENODEV; + goto error_close_mediadev; + } + link->setEnabled(true); + + link = imguMediaDev_->link(imguName, IMGU_PAD_VF, viewfinderName, 0); + if (!link) { + LOG(IPU3, Error) + << "Failed to get link '" << imguName << "':3 -> '" + << viewfinderName << "':0"; + ret = -ENODEV; + goto error_close_mediadev; + } + link->setEnabled(true); + + link = imguMediaDev_->link(imguName, IMGU_PAD_STAT, statName, 0); + if (!link) { + LOG(IPU3, Error) + << "Failed to get link '" << imguName << "':4 -> '" + << statName << "':0"; + ret = -ENODEV; + goto error_close_mediadev; + } + link->setEnabled(true); + + imguMediaDev_->close(); + + return 0; + +error_close_mediadev: + imguMediaDev_->close(); + + return ret; + +} + +V4L2Device *PipelineHandlerIPU3::openDevice(MediaDevice *media, + std::string &name) +{ + V4L2Device *dev; + + MediaEntity *entity = media->getEntityByName(name); + if (!entity) { + LOG(IPU3, Error) + << "Failed to get entity '" << name << "'"; + return nullptr; + } + + dev = new V4L2Device(entity); + if (dev->open()) + return nullptr; + + return dev; +} + +V4L2Subdevice *PipelineHandlerIPU3::openSubdevice(MediaDevice *media, + std::string &name) +{ + V4L2Subdevice *dev; + + MediaEntity *entity = media->getEntityByName(name); + if (!entity) { + LOG(IPU3, Error) + << "Failed to get entity '" << name << "'"; + return nullptr; + } + + dev = new V4L2Subdevice(entity); + if (dev->open()) + return nullptr; + + return dev; +} + +/* Create video devices and subdevices for the ImgU instance. */ +int PipelineHandlerIPU3::initImgu(ImguDevice *imgu) +{ + unsigned int index = imgu == &imgu0_ ? 0 : 1; + std::string imguName = "ipu3-imgu " + std::to_string(index); + std::string devName; + + imgu->imgu = openSubdevice(imguMediaDev_.get(), imguName); + if (!imgu->imgu) + return -ENODEV; + + devName = imguName + " input"; + imgu->input = openDevice(imguMediaDev_.get(), devName); + if (!imgu->input) + return -ENODEV; + + devName = imguName + " output"; + imgu->output = openDevice(imguMediaDev_.get(), devName); + if (!imgu->output) + return -ENODEV; + + devName = imguName + " viewfinder"; + imgu->viewfinder = openDevice(imguMediaDev_.get(), devName); + if (!imgu->viewfinder) + return -ENODEV; + + devName = imguName + " 3a stat"; + imgu->stat = openDevice(imguMediaDev_.get(), devName); + if (!imgu->stat) + return -ENODEV; + + return 0; +} + int PipelineHandlerIPU3::initCio2(unsigned int index, Cio2Device *cio2) { int ret; @@ -400,16 +603,8 @@ int PipelineHandlerIPU3::initCio2(unsigned int index, Cio2Device *cio2) return ret; std::string cio2Name = "ipu3-cio2 " + std::to_string(index); - entity = cio2MediaDev_->getEntityByName(cio2Name); - if (!entity) { - LOG(IPU3, Error) - << "Failed to get entity '" << cio2Name << "'"; - return -EINVAL; - } - - cio2->output = new V4L2Device(entity); - ret = cio2->output->open(); - if (ret) + cio2->output = openDevice(cio2MediaDev_.get(), cio2Name); + if (!cio2->output) return ret; return 0; From patchwork Thu Feb 28 20:04:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 682 Return-Path: Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 18B79610C4 for ; Thu, 28 Feb 2019 21:03:49 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id 99781E0005; Thu, 28 Feb 2019 20:03:48 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Feb 2019 21:04:04 +0100 Message-Id: <20190228200410.3022-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190228200410.3022-1-jacopo@jmondi.org> References: <20190228200410.3022-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 04/10] libcamera: ipu3: Propagate image format X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Feb 2019 20:03:49 -0000 Apply the requested image format to the sensor device, and apply the adjusted one to the CIO2 device, the ImgU subdevice and its input and output video devices. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 257 +++++++++++++++++++++++---- 1 file changed, 224 insertions(+), 33 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 9fa59c1bc97e..1e89e57f628b 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -8,11 +8,14 @@ #include #include +#include + #include #include #include #include "device_enumerator.h" +#include "geometry.h" #include "log.h" #include "media_device.h" #include "pipeline_handler.h" @@ -106,6 +109,29 @@ private: PipelineHandler::cameraData(camera)); } + void printDevFormat(const V4L2Device *dev, const V4L2DeviceFormat &fmt) + { + LOG(IPU3, Info) + << dev->deviceNode() << ": " << fmt.width << "x" + << fmt.height << "- 0x" << std::hex << fmt.fourcc + << " planes: " << fmt.planesCount; + } + + void printSubdevFormat(const V4L2Subdevice *dev, unsigned int pad, + const V4L2SubdeviceFormat &fmt) + { + LOG(IPU3, Info) + << "'" << dev->deviceName() << "':" << pad << " = " + << fmt.width << "x" << fmt.height << " - 0x" + << std::hex << fmt.mbus_code; + } + + int setImguFormat(V4L2Subdevice *imgu, + const StreamConfiguration &config, + Rectangle *rect); + int setSensorFormat(V4L2Subdevice *sensor, + const StreamConfiguration &config, + V4L2SubdeviceFormat *format); int linkImgu(ImguDevice *imgu); V4L2Device *openDevice(MediaDevice *media, std::string &name); @@ -186,14 +212,29 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, std::map &config) { IPU3CameraData *data = cameraData(camera); - StreamConfiguration *cfg = &config[&data->stream_]; - V4L2Subdevice *sensor = data->cio2.sensor; + const StreamConfiguration &cfg = config[&data->stream_]; V4L2Subdevice *csi2 = data->cio2.csi2; V4L2Device *cio2 = data->cio2.output; - V4L2SubdeviceFormat subdevFormat = {}; - V4L2DeviceFormat devFormat = {}; int ret; + /* + * Verify that the requested size respects the IPU3 alignement + * requirements: image size shall be 8-aligned in width and 4-aligned + * in height. + * + * TODO: consider the BDS scaling factor requirements: "the downscaling + * factor must be an integer value multiple of 1/32" + */ + if (cfg.width % 8 || cfg.height % 4) { + LOG(IPU3, Error) << "Stream format not support: bad alignement"; + return -EINVAL; + } + + LOG(IPU3, Info) + << "Camera :'" << camera->name() << " - Stream format: " + << cfg.width << "x" << cfg.height << " - " + << std::hex << cfg.pixelFormat; + /* * TODO: dynamically assign ImgU devices; as of now, with a single * stream supported, always use 'imgu0'. @@ -203,52 +244,73 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, if (ret) return ret; + V4L2Device *viewfinder = data->imgu->viewfinder; + V4L2Subdevice *sensor = data->cio2.sensor; + V4L2Device *output = data->imgu->output; + V4L2Subdevice *imgu = data->imgu->imgu; + V4L2Device *input = data->imgu->input; + /* - * FIXME: as of now, the format gets applied to the sensor and is - * propagated along the pipeline. It should instead be applied on the - * capture device and the sensor format calculated accordingly. + * Pass the requested output image size to the sensor and get back the + * adjusted one to be propagated to the CIO2 device and to the ImgU + * input. */ + V4L2SubdeviceFormat sensorFormat = {}; + ret = setSensorFormat(sensor, cfg, &sensorFormat); + if (ret) { + LOG(IPU3, Error) << "Stream format not supported: "; + return ret; + } + printSubdevFormat(sensor, 0, sensorFormat); - ret = sensor->getFormat(0, &subdevFormat); + ret = csi2->setFormat(0, &sensorFormat); if (ret) return ret; - - subdevFormat.width = cfg->width; - subdevFormat.height = cfg->height; - ret = sensor->setFormat(0, &subdevFormat); + printSubdevFormat(csi2, 0, sensorFormat); + + /* Apply the CIO2 image format to the CIO2 output and ImgU input. */ + V4L2DeviceFormat cio2Format = {}; + cio2Format.width = sensorFormat.width; + cio2Format.height = sensorFormat.height; + cio2Format.fourcc = V4L2_PIX_FMT_IPU3_SGRBG10; + cio2Format.planesCount = 1; + ret = cio2->setFormat(&cio2Format); if (ret) return ret; + printDevFormat(cio2, cio2Format); - /* Return error if the requested format cannot be applied to sensor. */ - if (subdevFormat.width != cfg->width || - subdevFormat.height != cfg->height) { - LOG(IPU3, Error) - << "Failed to apply image format " - << subdevFormat.width << "x" << subdevFormat.height - << " - got: " << cfg->width << "x" << cfg->height; - return -EINVAL; - } - - ret = csi2->setFormat(0, &subdevFormat); + ret = input->setFormat(&cio2Format); if (ret) return ret; - - ret = cio2->getFormat(&devFormat); + printDevFormat(input, cio2Format); + + /* Apply pad formats and crop/compose rectangle to the ImgU. */ + Rectangle rect = { + .x = 0, + .y = 0, + .w = cio2Format.width, + .h = cio2Format.height, + }; + ret = setImguFormat(imgu, cfg, &rect); if (ret) return ret; - devFormat.width = subdevFormat.width; - devFormat.height = subdevFormat.height; - devFormat.fourcc = cfg->pixelFormat; + /* Apply the format to the ImgU output and viewfinder devices. */ + V4L2DeviceFormat outputFormat = {}; + outputFormat.width = cfg.width; + outputFormat.height = cfg.height; + outputFormat.fourcc = V4L2_PIX_FMT_NV12; + outputFormat.planesCount = 2; - ret = cio2->setFormat(&devFormat); + ret = output->setFormat(&outputFormat); if (ret) return ret; + printDevFormat(output, outputFormat); - LOG(IPU3, Info) << cio2->driverName() << ": " - << devFormat.width << "x" << devFormat.height - << "- 0x" << std::hex << devFormat.fourcc << " planes: " - << devFormat.planes; + ret = viewfinder->setFormat(&outputFormat); + if (ret) + return ret; + printDevFormat(viewfinder, outputFormat); return 0; } @@ -409,6 +471,135 @@ error_release_mdev: return false; } +int PipelineHandlerIPU3::setImguFormat(V4L2Subdevice *imgu, + const StreamConfiguration &config, + Rectangle *rect) +{ + int ret; + + /* + * Configure the 'imgu' subdevice with the requested sizes. + * + * FIXME: the IPU3 driver implementation shall be changed to use the + * actual input sizes as 'imgu input' subdevice sizes, and use the + * desired output sizes to configure the crop/compose rectangles. The + * current implementation uses output sizes as 'imgu input' sizes, and + * uses the input dimension to configure the crop/compose rectangles, + * which contradicts the V4L2 specifications. + */ + ret = imgu->setCrop(IMGU_PAD_INPUT, rect); + if (ret) + return ret; + + LOG(IPU3, Info) + << "'" << imgu->deviceName() << "':" << IMGU_PAD_INPUT + << " = crop: (0,0)/" << rect->w << "x" << rect->h; + + ret = imgu->setCompose(IMGU_PAD_INPUT, rect); + if (ret) + return ret; + + LOG(IPU3, Info) + << "'" << imgu->deviceName() << "':" << IMGU_PAD_INPUT + << " = compose: (0,0)/" << rect->w << "x" << rect->h; + + + V4L2SubdeviceFormat imguFormat = {}; + imguFormat.width = config.width; + imguFormat.height = config.height; + imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED; + + ret = imgu->setFormat(IMGU_PAD_INPUT, &imguFormat); + if (ret) + return ret; + printSubdevFormat(imgu, IMGU_PAD_INPUT, imguFormat); + + ret = imgu->setFormat(IMGU_PAD_OUTPUT, &imguFormat); + if (ret) + return ret; + printSubdevFormat(imgu, IMGU_PAD_OUTPUT, imguFormat); + + ret = imgu->setFormat(IMGU_PAD_VF, &imguFormat); + if (ret) + return ret; + printSubdevFormat(imgu, IMGU_PAD_VF, imguFormat); + + ret = imgu->setFormat(IMGU_PAD_STAT, &imguFormat); + if (ret) + return ret; + printSubdevFormat(imgu, IMGU_PAD_STAT, imguFormat); + + return 0; +} + +int PipelineHandlerIPU3::setSensorFormat(V4L2Subdevice *sensor, + const StreamConfiguration &config, + V4L2SubdeviceFormat *format) +{ + std::map> formats; + unsigned int best = ~0; + bool found = false; + int ret; + + formats = sensor->formats(0); + if (formats.empty()) { + /* + * If the format list is empty, try with the currently + * applied one. + */ + ret = sensor->getFormat(0, format); + if (ret) + return ret; + + if (format->width < config.width || + format->height < config.height) + return -EINVAL; + + return 0; + } + + /* Search for the best approximation the sensor can provide. */ + auto it = formats.begin(); + while (it != formats.end()) { + for (SizeRange &size : it->second) { + if (size.maxWidth < config.width || + size.maxHeight < config.height) + continue; + + unsigned int diff = + (abs(size.maxWidth - config.width) + + abs(size.maxHeight - config.height)); + if (diff >= best) + continue; + + best = diff; + found = true; + + format->width = size.maxWidth; + format->height = size.maxHeight; + format->mbus_code = it->first; + } + + ++it; + } + if (!found) + return -EINVAL; + + ret = sensor->setFormat(0, format); + if (ret) + return ret; + + /* + * Make sure everything is all right and the format did not get + * adjusted. + */ + if (format->width < config.width || + format->height < config.height) + return -EINVAL; + + return 0; +} + /* Link entities in the ImgU unit to prepare for capture operations. */ int PipelineHandlerIPU3::linkImgu(ImguDevice *imguDevice) { From patchwork Thu Feb 28 20:04:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 683 Return-Path: Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AFE91610BB for ; Thu, 28 Feb 2019 21:03:49 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id 43B74E0005; Thu, 28 Feb 2019 20:03:49 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Feb 2019 21:04:05 +0100 Message-Id: <20190228200410.3022-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190228200410.3022-1-jacopo@jmondi.org> References: <20190228200410.3022-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 05/10] libcamera: ipu3: Implement buffer allocation X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Feb 2019 20:03:49 -0000 Implement buffer allocation in IPU3 pipeline handlers. As the pipeline handler supports a single stream, preprare two buffer pools for 'viewfinder' and 'stat' video devices, and export the 'output' video device buffers to the Stream's pool. Share buffers between the CIO2 output and the ImgU input video devices, as the output of the former should immediately be provided to the latter for further processing. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 47 ++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 1e89e57f628b..c7b7973952a0 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -47,6 +47,9 @@ struct ImguDevice { V4L2Device *viewfinder; V4L2Device *stat; /* TODO: add param video device for 3A tuning */ + + BufferPool vfPool; + BufferPool statPool; }; struct Cio2Device { @@ -63,6 +66,8 @@ struct Cio2Device { V4L2Device *output; V4L2Subdevice *csi2; V4L2Subdevice *sensor; + + BufferPool pool; }; class IPU3CameraData : public CameraData @@ -319,18 +324,48 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) { const StreamConfiguration &cfg = stream->configuration(); IPU3CameraData *data = cameraData(camera); + V4L2Device *viewfinder = data->imgu->viewfinder; + V4L2Device *output = data->imgu->output; + V4L2Device *input = data->imgu->input; V4L2Device *cio2 = data->cio2.output; + V4L2Device *stat = data->imgu->stat; + int ret; - if (!cfg.bufferCount) + if (!cfg.bufferCount) { + LOG(IPU3, Error) + << "Invalid number of buffers: "<< cfg.bufferCount; return -EINVAL; - - int ret = cio2->exportBuffers(&stream->bufferPool()); - if (ret) { - LOG(IPU3, Error) << "Failed to request memory"; - return ret; } + /* Share buffers between CIO2 output and ImgU input. */ + data->cio2.pool.createBuffers(IPU3_BUF_NUM); + ret = cio2->exportBuffers(&data->cio2.pool); + if (ret) + goto error_reserve_memory; + input->importBuffers(&data->cio2.pool); + + /* Prepare the buffer pools for viewfinder and stat. */ + data->imgu->vfPool.createBuffers(IPU3_BUF_NUM); + ret = viewfinder->exportBuffers(&data->imgu->vfPool); + if (ret) + goto error_reserve_memory; + + data->imgu->statPool.createBuffers(IPU3_BUF_NUM); + ret = stat->exportBuffers(&data->imgu->statPool); + if (ret) + goto error_reserve_memory; + + /* Export ImgU output buffers to the stream's pool. */ + ret = output->exportBuffers(&stream->bufferPool()); + if (ret) + goto error_reserve_memory; + return 0; + +error_reserve_memory: + LOG(IPU3, Error) << "Failed to reserve memory"; + + return ret; } int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) From patchwork Thu Feb 28 20:04:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 684 Return-Path: Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4E836610BA for ; Thu, 28 Feb 2019 21:03:50 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id D8C20E0006; Thu, 28 Feb 2019 20:03:49 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Feb 2019 21:04:06 +0100 Message-Id: <20190228200410.3022-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190228200410.3022-1-jacopo@jmondi.org> References: <20190228200410.3022-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 06/10] libcamera: ipu3: Implement buffer release X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Feb 2019 20:03:50 -0000 Release buffers on all video devices in the pipeline. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 40 +++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index c7b7973952a0..60a48859b398 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -145,6 +145,8 @@ private: int initCio2(unsigned int index, Cio2Device *cio2); void registerCameras(); + int releaseBuffers(V4L2Device *dev); + ImguDevice imgu0_; ImguDevice imgu1_; @@ -371,13 +373,32 @@ error_reserve_memory: int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) { IPU3CameraData *data = cameraData(camera); + V4L2Device *viewfinder = data->imgu->viewfinder; + V4L2Device *output = data->imgu->output; + V4L2Device *input = data->imgu->input; V4L2Device *cio2 = data->cio2.output; + V4L2Device *stat = data->imgu->stat; + int ret; - int ret = cio2->releaseBuffers(); - if (ret) { - LOG(IPU3, Error) << "Failed to release memory"; + ret = releaseBuffers(viewfinder); + if (ret) + return ret; + + ret = releaseBuffers(stat); + if (ret) + return ret; + + ret = releaseBuffers(output); + if (ret) + return ret; + + ret = releaseBuffers(cio2); + if (ret) + return ret; + + ret = releaseBuffers(input); + if (ret) return ret; - } return 0; } @@ -877,6 +898,17 @@ void PipelineHandlerIPU3::registerCameras() } } +int PipelineHandlerIPU3::releaseBuffers(V4L2Device *dev) +{ + int ret = dev->releaseBuffers(); + if (ret) { + LOG(IPU3, Error) << "Failed to release memory"; + return ret; + } + + return 0; +} + REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3); } /* namespace libcamera */ From patchwork Thu Feb 28 20:04:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 685 Return-Path: Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E4818610C5 for ; Thu, 28 Feb 2019 21:03:50 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id 78013E0005; Thu, 28 Feb 2019 20:03:50 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Feb 2019 21:04:07 +0100 Message-Id: <20190228200410.3022-8-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190228200410.3022-1-jacopo@jmondi.org> References: <20190228200410.3022-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 07/10] libcamera: ipu3: Queue requests to the pipeline X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Feb 2019 20:03:51 -0000 Implement queueRequest for the IPU3 pipeline manager. When a request is queued, a new buffer is queued to the ImgU output and the CIO2 output. Also queue buffers for the viewfinder and stat video nodes, even if they're not used at the moment. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 60a48859b398..8ce661e27f62 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -152,11 +152,15 @@ private: std::shared_ptr cio2MediaDev_; std::shared_ptr imguMediaDev_; + + unsigned int tmpBufferCount; }; PipelineHandlerIPU3::PipelineHandlerIPU3(CameraManager *manager) : PipelineHandler(manager), cio2MediaDev_(nullptr), imguMediaDev_(nullptr) { + /* FIXME: this is an hack. */ + tmpBufferCount = 0; } PipelineHandlerIPU3::~PipelineHandlerIPU3() @@ -430,9 +434,30 @@ void PipelineHandlerIPU3::stop(const Camera *camera) int PipelineHandlerIPU3::queueRequest(const Camera *camera, Request *request) { IPU3CameraData *data = cameraData(camera); + V4L2Device *viewfinder = data->imgu->viewfinder; + V4L2Device *output = data->imgu->output; V4L2Device *cio2 = data->cio2.output; + V4L2Device *stat = data->imgu->stat; Stream *stream = &data->stream_; + Buffer *tmpBuffer; + + /* + * Queue buffer on VF and stat. + * FIXME: this is an hack! + */ + tmpBuffer = &data->imgu->vfPool.buffers()[tmpBufferCount]; + viewfinder->queueBuffer(tmpBuffer); + + tmpBuffer = &data->imgu->statPool.buffers()[tmpBufferCount]; + stat->queueBuffer(tmpBuffer); + + tmpBuffer = &data->cio2.pool.buffers()[tmpBufferCount]; + cio2->queueBuffer(tmpBuffer); + + tmpBufferCount++; + tmpBufferCount %= IPU3_BUF_NUM; + /* Queue a buffer to the ImgU output for capture. */ Buffer *buffer = request->findBuffer(stream); if (!buffer) { LOG(IPU3, Error) @@ -440,7 +465,7 @@ int PipelineHandlerIPU3::queueRequest(const Camera *camera, Request *request) return -ENOENT; } - cio2->queueBuffer(buffer); + output->queueBuffer(buffer); return 0; } From patchwork Thu Feb 28 20:04:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 686 Return-Path: Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 85FDD610BB for ; Thu, 28 Feb 2019 21:03:51 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id 17E2AE0005; Thu, 28 Feb 2019 20:03:50 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Feb 2019 21:04:08 +0100 Message-Id: <20190228200410.3022-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190228200410.3022-1-jacopo@jmondi.org> References: <20190228200410.3022-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 08/10] libcamera: ipu3: Implement camera start/stop X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Feb 2019 20:03:52 -0000 Start and stop all video devices in the pipeline. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 57 ++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 8ce661e27f62..b9bc992879f5 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -146,6 +146,8 @@ private: void registerCameras(); int releaseBuffers(V4L2Device *dev); + int startDevice(V4L2Device *dev); + int stopDevice(V4L2Device *dev); ImguDevice imgu0_; ImguDevice imgu1_; @@ -410,14 +412,27 @@ int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) int PipelineHandlerIPU3::start(const Camera *camera) { IPU3CameraData *data = cameraData(camera); - V4L2Device *cio2 = data->cio2.output; int ret; - ret = cio2->streamOn(); - if (ret) { - LOG(IPU3, Info) << "Failed to start camera " << camera->name(); + ret = startDevice(data->imgu->output); + if (ret) + return ret; + + ret = startDevice(data->imgu->viewfinder); + if (ret) + return ret; + + ret = startDevice(data->imgu->stat); + if (ret) + return ret; + + ret = startDevice(data->imgu->input); + if (ret) + return ret; + + ret = startDevice(data->cio2.output); + if (ret) return ret; - } return 0; } @@ -425,10 +440,12 @@ int PipelineHandlerIPU3::start(const Camera *camera) void PipelineHandlerIPU3::stop(const Camera *camera) { IPU3CameraData *data = cameraData(camera); - V4L2Device *cio2 = data->cio2.output; - if (cio2->streamOff()) - LOG(IPU3, Info) << "Failed to stop camera " << camera->name(); + stopDevice(data->imgu->output); + stopDevice(data->imgu->viewfinder); + stopDevice(data->imgu->stat); + stopDevice(data->imgu->input); + stopDevice(data->cio2.output); } int PipelineHandlerIPU3::queueRequest(const Camera *camera, Request *request) @@ -934,6 +951,30 @@ int PipelineHandlerIPU3::releaseBuffers(V4L2Device *dev) return 0; } +int PipelineHandlerIPU3::startDevice(V4L2Device *dev) +{ + int ret = dev->streamOn(); + if (ret) { + LOG(IPU3, Info) + << "Failed to start video device:" << dev->deviceNode(); + return ret; + } + + return 0; +} + +int PipelineHandlerIPU3::stopDevice(V4L2Device *dev) +{ + int ret = dev->streamOff(); + if (ret) { + LOG(IPU3, Info) + << "Failed to stop video device:" << dev->deviceNode(); + return ret; + } + + return 0; +} + REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3); } /* namespace libcamera */ From patchwork Thu Feb 28 20:04:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 687 Return-Path: Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 22AF6610C0 for ; Thu, 28 Feb 2019 21:03:52 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id A9E0AE0004; Thu, 28 Feb 2019 20:03:51 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Feb 2019 21:04:09 +0100 Message-Id: <20190228200410.3022-10-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190228200410.3022-1-jacopo@jmondi.org> References: <20190228200410.3022-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 09/10] libcamera: ipu3: Connect CIO2 output to ImgU input X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Feb 2019 20:03:52 -0000 Connect the CIO2 output buffer available signal to a slot that simply queue the received buffer to ImgU for processing. FIXME: as long as the bufferReady signal cannot transport at least the cameraData from where to retrieve a pointer to the ImguDevice, store it as a class member. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index b9bc992879f5..3138eb0bf8b6 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -149,6 +149,8 @@ private: int startDevice(V4L2Device *dev); int stopDevice(V4L2Device *dev); + void cio2BufferDone(Buffer *buffer); + ImguDevice imgu0_; ImguDevice imgu1_; @@ -156,6 +158,7 @@ private: std::shared_ptr imguMediaDev_; unsigned int tmpBufferCount; + IPU3CameraData *tmpCameraData; }; PipelineHandlerIPU3::PipelineHandlerIPU3(CameraManager *manager) @@ -430,6 +433,19 @@ int PipelineHandlerIPU3::start(const Camera *camera) if (ret) return ret; + /* + * FIXME + * This is a big hack! tmpCameraData is used in the cio2BufferDone + * slot, as there is currently no way to access cameraData from there. + */ + tmpCameraData = data; + + /* + * Connect CIO2 output and ImgU input buffer events, when a buffer + * is available from CIO2, queue it to the ImgU. + */ + data->cio2.output->bufferReady.connect(this, + &PipelineHandlerIPU3::cio2BufferDone); ret = startDevice(data->cio2.output); if (ret) return ret; @@ -975,6 +991,13 @@ int PipelineHandlerIPU3::stopDevice(V4L2Device *dev) return 0; } +void PipelineHandlerIPU3::cio2BufferDone(Buffer *buffer) +{ + ImguDevice *imgu = tmpCameraData->imgu; + + imgu->input->queueBuffer(buffer); +} + REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3); } /* namespace libcamera */ From patchwork Thu Feb 28 20:04:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 688 Return-Path: Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B5CF1610BC for ; Thu, 28 Feb 2019 21:03:52 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id 4B123E0006; Thu, 28 Feb 2019 20:03:52 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Feb 2019 21:04:10 +0100 Message-Id: <20190228200410.3022-11-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190228200410.3022-1-jacopo@jmondi.org> References: <20190228200410.3022-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 10/10] libcamera: ipu3: Use NV12 as default image format X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Feb 2019 20:03:52 -0000 Now that images come from the ImgU output, hardcode NV12 as default output format. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 3138eb0bf8b6..660c00dacb2f 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -187,7 +187,7 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, V4L2Subdevice *sensor = data->cio2.sensor; StreamConfiguration *config = &configs[&data->stream_]; - config->pixelFormat = V4L2_PIX_FMT_IPU3_SGRBG10; + config->pixelFormat = V4L2_PIX_FMT_NV12; config->bufferCount = IPU3_BUF_NUM; /*