Message ID | 20190121150756.14982-2-jacopo@jmondi.org |
---|---|
State | Accepted |
Headers | show |
Series |
|
Related | show |
Hi Jacopo, Thank you for the patch. On Mon, Jan 21, 2019 at 04:07:55PM +0100, Jacopo Mondi wrote: > 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@jmondi.org> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > --- > 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 0000000..daf681c > --- /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 <memory> > +#include <vector> > + > +#include <libcamera/camera.h> > +#include <libcamera/camera_manager.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(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<MediaPad *> &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<MediaLink *> &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 = 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 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')
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp new file mode 100644 index 0000000..daf681c --- /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 <memory> +#include <vector> + +#include <libcamera/camera.h> +#include <libcamera/camera_manager.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(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<MediaPad *> &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<MediaLink *> &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 = 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 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')
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@jmondi.org> --- 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