[libcamera-devel] [PATCH v4 06/31] libcamera: ipu3: Initialize and configure ImgUs

Laurent Pinchart laurent.pinchart at ideasonboard.com
Thu Mar 21 10:33:25 CET 2019


Hi Jacopo,

Thank you for the patch.

On Wed, Mar 20, 2019 at 05:30:30PM +0100, Jacopo Mondi wrote:
> 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.

s/camera/cameras/
s/in future/in the future/

> 
> Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
> ---
>  src/libcamera/pipeline/ipu3/ipu3.cpp | 223 +++++++++++++++++++++++++--
>  1 file changed, 209 insertions(+), 14 deletions(-)
> 
> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
> index 2e351d04a784..26fc56a76eb1 100644
> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp
> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
> @@ -27,6 +27,38 @@ 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_;

As this is the ImgUDevice class, maybe just "name_" ?

> +	MediaDevice *mediaDevice_;
> +
> +	V4L2Subdevice *imgu;
> +	V4L2Device *input;
> +	V4L2Device *output;
> +	V4L2Device *viewfinder;
> +	V4L2Device *stat;

Missing _ at the end of each variable.

> +	/* \todo Add param video device for 3A tuning */
> +};
> +
>  struct CIO2Device {
>  	CIO2Device()
>  		: output(nullptr), csi2(nullptr), sensor(nullptr)
> @@ -68,6 +100,7 @@ public:
>  	bool match(DeviceEnumerator *enumerator);
>  
>  private:
> +	static constexpr unsigned int IPU3_IMGU_COUNT = 2;
>  	static constexpr unsigned int IPU3_BUFFER_COUNT = 4;
>  
>  	class IPU3CameraData : public CameraData
> @@ -81,6 +114,7 @@ private:
>  		void bufferReady(Buffer *buffer);
>  
>  		CIO2Device cio2;
> +		ImgUDevice *imgu;

Here too.

>  
>  		Stream stream_;
>  	};
> @@ -92,10 +126,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_;
>  };
> @@ -355,11 +397,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:

There's a single error label, just call it error.

> +	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)
> @@ -378,6 +454,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.

Please do :-) You can create a static function in the V4L2Device class
that takes a media device and entity name and return a newly created
V4L2Device. I would however keep the open() call outside of the helper
as we'll need to refactor open/close later.

> + *
> + * \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.

I'd say the same here, but you use this helper in a single location, so
I would just inline it.

> + *
> + * \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;

Let's simplify this by removing the need for this code. The caller can
just propagate the error up, the match function will fail, and the imgu
instances will be destroyed.

> +
> +	return -ENODEV;
> +}
> +
>  /**
>   * \brief Initialize components of the CIO2 device \a index used by a camera
>   * \param index The CIO2 device index
> @@ -458,23 +642,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:
> @@ -483,6 +656,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;
> +}

I don't think this is needed for the reason explained above.

> +
>  /*
>   * Cameras are created associating an image sensor (represented by a
>   * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four
> @@ -495,7 +678,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_ };
> @@ -506,6 +689,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);

The imgus are separate from the cameras, please initialize them before
this loop, and return an error if initialization fails.

> +		if (ret) {
> +			deleteCIO2(cio2);
> +			continue;
> +		}
> +
>  		std::string cameraName = cio2->sensor->deviceName() + " "
>  				       + std::to_string(id);
>  		std::shared_ptr<Camera> camera = Camera::create(this,

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list