[libcamera-devel,v2,05/14] libcamera: ipu3: Initialize and configure ImgUs

Message ID 20190312121242.2253-6-jacopo@jmondi.org
State Superseded
Headers show
Series
  • libcamera: ipu3: ImgU support
Related show

Commit Message

Jacopo Mondi March 12, 2019, 12:12 p.m. UTC
Create video devices and subdevices associated with an ImgU unit at
camera registration time.

Statically assign imgu0 to the first camera and imgu1 to the second one
and limit support to two camera. This will have to be revised in future.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 src/libcamera/pipeline/ipu3/ipu3.cpp | 222 +++++++++++++++++++++++++--
 1 file changed, 208 insertions(+), 14 deletions(-)

Patch

diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 0a2516ac7d61..009ee341f18c 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -27,6 +27,37 @@  namespace libcamera {
 
 LOG_DEFINE_CATEGORY(IPU3)
 
+class ImgUDevice {
+public:
+	ImgUDevice()
+		: imgu(nullptr), input(nullptr), output(nullptr),
+		  viewfinder(nullptr), stat(nullptr)
+	{
+	}
+
+	~ImgUDevice()
+	{
+		delete imgu;
+		delete input;
+		delete output;
+		delete viewfinder;
+		delete stat;
+	}
+
+	void init(MediaDevice *media, unsigned int index);
+
+	unsigned int index_;
+	std::string imguName_;
+	MediaDevice *mediaDevice_;
+
+	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)
@@ -56,6 +87,7 @@  public:
 	void bufferReady(Buffer *buffer);
 
 	CIO2Device cio2;
+	ImgUDevice *imgu;
 
 	Stream stream_;
 };
@@ -83,6 +115,7 @@  public:
 	bool match(DeviceEnumerator *enumerator);
 
 private:
+	static constexpr unsigned int IPU3_IMGU_COUNT = 2;
 	static constexpr unsigned int IPU3_BUFFER_COUNT = 4;
 
 	IPU3CameraData *cameraData(const Camera *camera)
@@ -92,10 +125,18 @@  private:
 	}
 
 	int mediaBusToCIO2Format(unsigned int code);
+	V4L2Device *openDevice(MediaDevice *media, const std::string &name);
+	V4L2Subdevice *openSubdevice(MediaDevice *media,
+				     const std::string &name);
 
 	int initCIO2(unsigned int index, CIO2Device *cio2);
+	void deleteCIO2(CIO2Device *cio2);
+
+	int initImgU(ImgUDevice *imgu);
+
 	void registerCameras();
 
+	ImgUDevice imgus_[IPU3_IMGU_COUNT];
 	std::shared_ptr<MediaDevice> cio2MediaDev_;
 	std::shared_ptr<MediaDevice> imguMediaDev_;
 };
@@ -360,11 +401,45 @@  bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator)
 		return false;
 	}
 
+	if (imguMediaDev_->open()) {
+		cio2MediaDev_->close();
+		return false;
+	}
+
+	if (imguMediaDev_->disableLinks())
+		goto error_close_mdev;
+
+	for (unsigned int i = 0; i < IPU3_IMGU_COUNT; ++i)
+		imgus_[i].init(imguMediaDev_.get(), i);
+
 	registerCameras();
 
 	cio2MediaDev_->close();
+	imguMediaDev_->close();
 
 	return true;
+
+error_close_mdev:
+	cio2MediaDev_->close();
+	imguMediaDev_->close();
+
+	return false;
+}
+
+/* ----------------------------------------------------------------------------
+ * Helpers
+ */
+
+/**
+ * \brief Initialize fields of the ImgU instance
+ * \param mediaDevice The ImgU instance media device
+ * \param index The ImgU instance index
+ */
+void ImgUDevice::init(MediaDevice *mediaDevice, unsigned int index)
+{
+	index_ = index;
+	imguName_ = "ipu3-imgu " + std::to_string(index_);
+	mediaDevice_ = mediaDevice;
 }
 
 int PipelineHandlerIPU3::mediaBusToCIO2Format(unsigned int code)
@@ -411,6 +486,114 @@  int PipelineHandlerIPU3::mediaBusToCIO2Format(unsigned int code)
 	}
 }
 
+/**
+ * \brief Create and open the video device with \a name in media device \a media
+ *
+ * \todo Make a generic helper out of this method.
+ *
+ * \return Pointer to the video device on success, nullptr otherwise
+ */
+V4L2Device *PipelineHandlerIPU3::openDevice(MediaDevice *media,
+					    const std::string &name)
+{
+	MediaEntity *entity = media->getEntityByName(name);
+	if (!entity) {
+		LOG(IPU3, Error)
+			<< "Failed to get entity '" << name << "'";
+		return nullptr;
+	}
+
+	V4L2Device *dev = new V4L2Device(entity);
+	if (dev->open()) {
+		delete dev;
+		return nullptr;
+	}
+
+	return dev;
+}
+
+/**
+ * \brief Create and open the subdevice with \a name in media device \a media
+ *
+ * \todo Make a generic helper out of this method.
+ *
+ * \return Pointer to the subdevice on success, nullptr otherwise
+ */
+V4L2Subdevice *PipelineHandlerIPU3::openSubdevice(MediaDevice *media,
+						  const std::string &name)
+{
+	MediaEntity *entity = media->getEntityByName(name);
+	if (!entity) {
+		LOG(IPU3, Error)
+			<< "Failed to get entity '" << name << "'";
+		return nullptr;
+	}
+
+	V4L2Subdevice *dev = new V4L2Subdevice(entity);
+	if (dev->open()) {
+		delete dev;
+		return nullptr;
+	}
+
+	return dev;
+}
+
+/* ----------------------------------------------------------------------------
+ * IPU3 pipeline configuration
+ */
+
+/**
+ * \brief Initialize and configure components of the ImgU instance
+ *
+ * Create and open the devices and subdevices in the ImgU instance.
+ * This methods configures the ImgU instance for capture operations, and
+ * should be called at stream configuration time.
+ *
+ * \todo Expand the ImgU configuration with controls setting
+ *
+ * \return 0 on success or a negative error code otherwise
+ * \retval -ENODEV Failed to open one of the video devices or subdevices
+ */
+int PipelineHandlerIPU3::initImgU(ImgUDevice *imgu)
+{
+	imgu->imgu = openSubdevice(imgu->mediaDevice_, imgu->imguName_);
+	if (!imgu->imgu)
+		return -ENODEV;
+
+	imgu->input = openDevice(imgu->mediaDevice_,
+				 imgu->imguName_ + " input");
+	if (!imgu->input)
+		goto error_delete_imgu;
+
+	imgu->output = openDevice(imgu->mediaDevice_,
+				  imgu->imguName_ + " output");
+	if (!imgu->output)
+		goto error_delete_input;
+
+	imgu->viewfinder = openDevice(imgu->mediaDevice_,
+				      imgu->imguName_ + " viewfinder");
+	if (!imgu->viewfinder)
+		goto error_delete_output;
+
+	imgu->stat = openDevice(imgu->mediaDevice_,
+				imgu->imguName_ + " 3a stat");
+	if (!imgu->stat)
+		goto error_delete_vf;
+
+	return 0;
+
+error_delete_vf:
+	delete imgu->viewfinder;
+error_delete_output:
+	delete imgu->output;
+error_delete_input:
+	delete imgu->input;
+error_delete_imgu:
+	delete imgu->imgu;
+
+	return -ENODEV;
+}
+
 /**
  * \brief Initialize components of the CIO2 device \a index used by a camera
  * \param index The CIO2 device index
@@ -475,23 +658,12 @@  int PipelineHandlerIPU3::initCIO2(unsigned int index, CIO2Device *cio2)
 	if (ret)
 		goto error_delete_csi2;
 
-	entity = cio2MediaDev_->getEntityByName(cio2Name);
-	if (!entity) {
-		LOG(IPU3, Error)
-			<< "Failed to get entity '" << cio2Name << "'";
-		ret = -EINVAL;
+	cio2->output = openDevice(cio2MediaDev_.get(), cio2Name);
+	if (!cio2->output)
 		goto error_delete_csi2;
-	}
-
-	cio2->output = new V4L2Device(entity);
-	ret = cio2->output->open();
-	if (ret)
-		goto error_delete_output;
 
 	return 0;
 
-error_delete_output:
-	delete cio2->output;
 error_delete_csi2:
 	delete cio2->csi2;
 error_delete_sensor:
@@ -500,6 +672,16 @@  error_delete_sensor:
 	return ret;
 }
 
+/**
+ * \brief Delete all devices associated with a CIO2 unit
+ */
+void PipelineHandlerIPU3::deleteCIO2(CIO2Device *cio2)
+{
+	delete cio2->output;
+	delete cio2->csi2;
+	delete cio2->sensor;
+}
+
 /*
  * Cameras are created associating an image sensor (represented by a
  * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four
@@ -512,7 +694,7 @@  void PipelineHandlerIPU3::registerCameras()
 	 * image sensor is connected to it.
 	 */
 	unsigned int numCameras = 0;
-	for (unsigned int id = 0; id < 4; ++id) {
+	for (unsigned int id = 0; id < 4 && numCameras < 2; ++id) {
 		std::unique_ptr<IPU3CameraData> data =
 			utils::make_unique<IPU3CameraData>(this);
 		std::set<Stream *> streams{ &data->stream_ };
@@ -523,6 +705,18 @@  void PipelineHandlerIPU3::registerCameras()
 		if (ret)
 			continue;
 
+		/**
+		 * \todo Dynamically assign ImgU devices; as of now, limit
+		 * support to two cameras only, and assign imgu0 to the first
+		 * one and imgu1 to the second.
+		 */
+		data->imgu = &imgus_[numCameras];
+		ret = initImgU(data->imgu);
+		if (ret) {
+			deleteCIO2(cio2);
+			continue;
+		}
+
 		std::string cameraName = cio2->sensor->deviceName() + " "
 				       + std::to_string(id);
 		std::shared_ptr<Camera> camera =