From 93734d7fe0d90296a9e7715ae12cbf1579fd7dd5 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 11 Jan 2019 17:39:55 +0100 Subject: libcamera: pipeline: Add Intel IPU3 pipeline Add a pipeline handler for the Intel IPU3 device. The pipeline handler creates a Camera for each image sensor it finds to be connected to an IPU3 CSI-2 receiver, and enables the link between the two. Tested on Soraka, listing detected cameras on the system, verifying the pipeline handler gets matched and links properly enabled. Reviewed-by: Laurent Pinchart Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 185 ++++++++++++++++++++++++++++++++ src/libcamera/pipeline/ipu3/meson.build | 3 + src/libcamera/pipeline/meson.build | 2 + 3 files changed, 190 insertions(+) create mode 100644 src/libcamera/pipeline/ipu3/ipu3.cpp create mode 100644 src/libcamera/pipeline/ipu3/meson.build diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp new file mode 100644 index 00000000..daf681ce --- /dev/null +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -0,0 +1,185 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipu3.cpp - Pipeline handler for Intel IPU3 + */ + +#include +#include + +#include +#include + +#include "device_enumerator.h" +#include "log.h" +#include "media_device.h" +#include "pipeline_handler.h" + +namespace libcamera { + +class PipelineHandlerIPU3 : public PipelineHandler +{ +public: + PipelineHandlerIPU3(); + ~PipelineHandlerIPU3(); + + bool match(CameraManager *manager, DeviceEnumerator *enumerator); + +private: + MediaDevice *cio2_; + MediaDevice *imgu_; + + void registerCameras(CameraManager *manager); +}; + +PipelineHandlerIPU3::PipelineHandlerIPU3() + : cio2_(nullptr), imgu_(nullptr) +{ +} + +PipelineHandlerIPU3::~PipelineHandlerIPU3() +{ + if (cio2_) + cio2_->release(); + + if (imgu_) + imgu_->release(); + + cio2_ = nullptr; + imgu_ = nullptr; +} + +bool PipelineHandlerIPU3::match(CameraManager *manager, DeviceEnumerator *enumerator) +{ + DeviceMatch cio2_dm("ipu3-cio2"); + cio2_dm.add("ipu3-csi2 0"); + cio2_dm.add("ipu3-cio2 0"); + cio2_dm.add("ipu3-csi2 1"); + cio2_dm.add("ipu3-cio2 1"); + cio2_dm.add("ipu3-csi2 2"); + cio2_dm.add("ipu3-cio2 2"); + cio2_dm.add("ipu3-csi2 3"); + cio2_dm.add("ipu3-cio2 3"); + + DeviceMatch imgu_dm("ipu3-imgu"); + imgu_dm.add("ipu3-imgu 0"); + imgu_dm.add("ipu3-imgu 0 input"); + imgu_dm.add("ipu3-imgu 0 parameters"); + imgu_dm.add("ipu3-imgu 0 output"); + imgu_dm.add("ipu3-imgu 0 viewfinder"); + imgu_dm.add("ipu3-imgu 0 3a stat"); + imgu_dm.add("ipu3-imgu 1"); + imgu_dm.add("ipu3-imgu 1 input"); + imgu_dm.add("ipu3-imgu 1 parameters"); + imgu_dm.add("ipu3-imgu 1 output"); + imgu_dm.add("ipu3-imgu 1 viewfinder"); + imgu_dm.add("ipu3-imgu 1 3a stat"); + + cio2_ = enumerator->search(cio2_dm); + if (!cio2_) + return false; + + imgu_ = enumerator->search(imgu_dm); + if (!imgu_) + 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(); + + /* + * Disable all links that are enabled by default on CIO2, as camera + * creation enables all valid links it finds. + * + * Close the CIO2 media device after, as links are enabled and should + * not need to be changed after. + */ + if (cio2_->open()) + goto error_release_mdev; + + if (cio2_->disableLinks()) + goto error_close_cio2; + + registerCameras(manager); + + cio2_->close(); + + return true; + +error_close_cio2: + cio2_->close(); + +error_release_mdev: + cio2_->release(); + imgu_->release(); + + return false; +} + +/* + * Cameras are created associating an image sensor (represented by a + * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four + * CIO2 CSI-2 receivers. + */ +void PipelineHandlerIPU3::registerCameras(CameraManager *manager) +{ + /* + * 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); + + /* + * 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::string cameraName = sensor->name() + " " + std::to_string(id); + std::shared_ptr camera = Camera::create(cameraName); + manager->addCamera(std::move(camera)); + + LOG(Info) << "Registered Camera[" << numCameras << "] \"" + << cameraName << "\"" + << " connected to CSI-2 receiver " << id; + + numCameras++; + } +} + +REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3); + +} /* namespace libcamera */ diff --git a/src/libcamera/pipeline/ipu3/meson.build b/src/libcamera/pipeline/ipu3/meson.build new file mode 100644 index 00000000..0ab766a2 --- /dev/null +++ b/src/libcamera/pipeline/ipu3/meson.build @@ -0,0 +1,3 @@ +libcamera_sources += files([ + 'ipu3.cpp', +]) diff --git a/src/libcamera/pipeline/meson.build b/src/libcamera/pipeline/meson.build index 615ecd20..811c075b 100644 --- a/src/libcamera/pipeline/meson.build +++ b/src/libcamera/pipeline/meson.build @@ -1,3 +1,5 @@ libcamera_sources += files([ 'vimc.cpp', ]) + +subdir('ipu3') -- cgit v1.2.1