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 <laurent.pinchart@ideasonboard.com>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
This commit is contained in:
Jacopo Mondi 2019-01-11 17:39:55 +01:00
parent 8b8ae52134
commit 93734d7fe0
3 changed files with 190 additions and 0 deletions

View file

@ -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 */

View file

@ -0,0 +1,3 @@
libcamera_sources += files([
'ipu3.cpp',
])

View file

@ -1,3 +1,5 @@
libcamera_sources += files([
'vimc.cpp',
])
subdir('ipu3')