[libcamera-devel] [PATCH 4/4] libcamera: pipeline: Add Intel IPU3 pipeline

Jacopo Mondi jacopo at jmondi.org
Tue Jan 15 15:07:49 CET 2019


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.

Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
---
 src/libcamera/pipeline/ipu3/ipu3.cpp    | 249 ++++++++++++++++++++++++
 src/libcamera/pipeline/ipu3/meson.build |   3 +
 src/libcamera/pipeline/meson.build      |   2 +
 3 files changed, 254 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 0000000..4c24c79
--- /dev/null
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -0,0 +1,249 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * ipu3.cpp - Pipeline handler for Intel IPU3
+ */
+
+#include <map>
+#include <vector>
+
+#include <libcamera/camera.h>
+
+#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(DeviceEnumerator *enumerator);
+
+	unsigned int count();
+	Camera *camera(unsigned int id) final;
+
+private:
+	MediaDevice *cio2_;
+	MediaDevice *imgu_;
+
+	unsigned int numCameras_;
+	std::map<unsigned int, Camera *> cameras_;
+
+	unsigned int registerCameras();
+};
+
+PipelineHandlerIPU3::PipelineHandlerIPU3()
+	: cio2_(nullptr), imgu_(nullptr), numCameras_(0)
+{
+}
+
+PipelineHandlerIPU3::~PipelineHandlerIPU3()
+{
+	if (cio2_)
+		cio2_->release();
+
+	if (imgu_)
+		imgu_->release();
+
+	for (auto camera : cameras_) {
+		if (!camera.second)
+			continue;
+
+		camera.second->put();
+
+		/*
+		 * FIXME
+		 * The lifetime management of Camera instances will be
+		 * soon changed: as of now, the handler creates cameras, and
+		 * -shall- destroy them as well to avoid leaks.
+		 */
+		delete camera.second;
+	}
+
+	cio2_ = nullptr;
+	imgu_ = nullptr;
+	cameras_.clear();
+}
+
+unsigned int PipelineHandlerIPU3::count()
+{
+	return numCameras_;
+}
+
+Camera *PipelineHandlerIPU3::camera(unsigned int id)
+{
+	if (id >= numCameras_)
+		return nullptr;
+
+	/*
+	 * The requested camera id does not match the key index used to store
+	 * Camera instances in the 'cameras_' map.
+	 *
+	 * The 'id' argument represent the n-th valid cameras registered
+	 * in the system, while the indexing key is the CSI-2 receiver index
+	 * the camera sensor is associated to, and some receiver might have no
+	 * camera sensor connected.
+	 */
+	for (auto it = cameras_.begin(); it != cameras_.end(); ++it, --id) {
+		if (id == 0)
+			return (*it).second;
+	}
+
+	return nullptr;
+}
+
+bool PipelineHandlerIPU3::match(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");
+
+	cio2_ = enumerator->search(cio2_dm);
+	if (!cio2_)
+		return false;
+
+	cio2_->acquire();
+
+	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");
+
+	imgu_ = enumerator->search(imgu_dm);
+	if (!imgu_) {
+		cio2_->release();
+		return false;
+	}
+
+	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()) {
+		cio2_->release();
+		imgu_->release();
+		return false;
+	}
+	cio2_->disableLinks();
+
+	numCameras_ = registerCameras();
+	LOG(Debug) << "\"Intel IPU3\" pipeline handler initialized with "
+		   << numCameras_ << " cameras registered";
+
+	cio2_->close();
+
+	return true;
+}
+
+/*
+ * 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.
+ *
+ * Cameras are here created and stored in the member field 'cameras_' map,
+ * indexed by the id of the CSI-2 receiver they are connected, to maintain
+ * an ordering that does not depend on the device enumeration order.
+ *
+ * The function returns the number of cameras found in the system.
+ */
+unsigned int PipelineHandlerIPU3::registerCameras()
+{
+	const std::vector<MediaEntity *> entities = cio2_->entities();
+	unsigned int numCameras = 0;
+	struct {
+		unsigned int id;
+		MediaEntity *csi2;
+	} csi2Receivers[] = {
+		{ 0, cio2_->getEntityByName("ipu3-csi2 0") },
+		{ 1, cio2_->getEntityByName("ipu3-csi2 1") },
+		{ 2, cio2_->getEntityByName("ipu3-csi2 2") },
+		{ 3, cio2_->getEntityByName("ipu3-csi2 3") },
+	};
+
+	/*
+	 * For each CSI-2 receiver on the IPU3, create a Camera if an
+	 * image sensor is connected to it.
+	 */
+	for (auto csi2Receiver : csi2Receivers) {
+		MediaEntity *csi2 = csi2Receiver.csi2;
+		unsigned int id = csi2Receiver.id;
+
+		/* IPU3 CSI-2 receivers have a single sink pad. */
+		std::vector<MediaPad *> pads = csi2->pads();
+		MediaPad *sink;
+		for (MediaPad *pad : pads) {
+			if (!(pad->flags() & MEDIA_PAD_FL_SINK))
+				continue;
+
+			sink = pad;
+			break;
+		}
+
+		/* Verify that the receiver is connected to a sensor. */
+		std::vector<MediaLink *> links = sink->links();
+		if (links.empty())
+			continue;
+
+		/*
+		 * FIXME
+		 * This supports creating a single camera per CSI-2 receiver.
+		 */
+		for (MediaLink *link : links) {
+			MediaEntity *sensor = link->source()->entity();
+			if (!sensor)
+				continue;
+
+			if (sensor->function() != MEDIA_ENT_F_CAM_SENSOR)
+				continue;
+
+			/* Enable the link between sensor and CSI-2 receiver. */
+			if (link->setEnabled(true))
+				continue;
+
+			/* Create the camera using the sensor name. */
+			std::size_t pos = sensor->name().find(" ");
+			std::string cameraName = sensor->name().substr(0, pos);
+
+			cameras_[id] = new Camera(cameraName);
+
+			LOG(Debug) << "Registered Camera[" << numCameras
+				   << "] \"" << cameraName << "\""
+				   << " connected to CSI-2 receiver " << id;
+
+			numCameras++;
+			break;
+		}
+	}
+
+	return 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 0000000..0ab766a
--- /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 615ecd2..811c075 100644
--- a/src/libcamera/pipeline/meson.build
+++ b/src/libcamera/pipeline/meson.build
@@ -1,3 +1,5 @@
 libcamera_sources += files([
     'vimc.cpp',
 ])
+
+subdir('ipu3')
-- 
2.20.1



More information about the libcamera-devel mailing list