@@ -14,11 +14,14 @@
#include <libcamera/camera.h>
#include <libcamera/control_ids.h>
#include <libcamera/formats.h>
+#include <libcamera/ipa/ipu3.h>
#include <libcamera/request.h>
#include <libcamera/stream.h>
#include "libcamera/internal/camera_sensor.h"
+#include "libcamera/internal/delayed_controls.h"
#include "libcamera/internal/device_enumerator.h"
+#include "libcamera/internal/ipa_manager.h"
#include "libcamera/internal/log.h"
#include "libcamera/internal/media_device.h"
#include "libcamera/internal/pipeline_handler.h"
@@ -54,6 +57,8 @@ public:
{
}
+ int loadIPA();
+
void imguOutputBufferReady(FrameBuffer *buffer);
void cio2BufferReady(FrameBuffer *buffer);
@@ -65,6 +70,10 @@ public:
Stream rawStream_;
uint32_t exposureTime_;
+ std::unique_ptr<DelayedControls> delayedCtrls_;
+
+private:
+ void queueFrameAction(unsigned int id, const IPAOperationData &op);
};
class IPU3CameraConfiguration : public CameraConfiguration
@@ -594,6 +603,13 @@ int PipelineHandlerIPU3::start(Camera *camera, [[maybe_unused]] ControlList *con
IPU3CameraData *data = cameraData(camera);
CIO2Device *cio2 = &data->cio2_;
ImgUDevice *imgu = data->imgu_;
+
+ CameraSensorInfo sensorInfo = {};
+ std::map<unsigned int, IPAStream> streamConfig;
+ std::map<unsigned int, const ControlInfoMap &> entityControls;
+ IPAOperationData ipaConfig;
+ IPAOperationData result = {};
+
int ret;
/* Allocate buffers for internal pipeline usage. */
@@ -601,6 +617,11 @@ int PipelineHandlerIPU3::start(Camera *camera, [[maybe_unused]] ControlList *con
if (ret)
return ret;
+ IPAOperationData ipaData = {};
+ ret = data->ipa_->start(ipaData, nullptr);
+ if (ret)
+ goto error;
+
/*
* Start the ImgU video devices, buffers will be queued to the
* ImgU output and viewfinder when requests will be queued.
@@ -613,11 +634,31 @@ int PipelineHandlerIPU3::start(Camera *camera, [[maybe_unused]] ControlList *con
if (ret)
goto error;
+ /* Inform IPA of stream configuration and sensor controls. */
+ ret = data->cio2_.sensor()->sensorInfo(&sensorInfo);
+ if (ret)
+ goto error;
+
+ streamConfig[0] = {
+ .pixelFormat = data->outStream_.configuration().pixelFormat,
+ .size = data->outStream_.configuration().size,
+ };
+ streamConfig[1] = {
+ .pixelFormat = data->vfStream_.configuration().pixelFormat,
+ .size = data->vfStream_.configuration().size,
+ };
+
+ entityControls.emplace(0, data->cio2_.sensor()->controls());
+
+ data->ipa_->configure(sensorInfo, streamConfig, entityControls,
+ ipaConfig, &result);
+
return 0;
error:
imgu->stop();
cio2->stop();
+ data->ipa_->stop();
freeBuffers(camera);
LOG(IPU3, Error) << "Failed to start camera " << camera->id();
@@ -634,6 +675,8 @@ void PipelineHandlerIPU3::stop(Camera *camera)
if (ret)
LOG(IPU3, Warning) << "Failed to stop camera " << camera->id();
+ data->ipa_->stop();
+
freeBuffers(camera);
}
@@ -883,6 +926,10 @@ int PipelineHandlerIPU3::registerCameras()
if (ret)
continue;
+ ret = data->loadIPA();
+ if (ret)
+ continue;
+
/* Initialize the camera properties. */
data->properties_ = cio2->sensor()->properties();
@@ -890,6 +937,22 @@ int PipelineHandlerIPU3::registerCameras()
if (ret)
continue;
+ /*
+ * \todo Read delay values from the sensor itself or from a
+ * a sensor database. For now use generic values taken from
+ * the Raspberry Pi and listed as 'generic values'.
+ */
+ std::unordered_map<uint32_t, unsigned int> delays = {
+ { V4L2_CID_ANALOGUE_GAIN, 1 },
+ { V4L2_CID_EXPOSURE, 2 },
+ };
+
+ data->delayedCtrls_ =
+ std::make_unique<DelayedControls>(cio2->sensor()->device(),
+ delays);
+ data->cio2_.frameStart().connect(data->delayedCtrls_.get(),
+ &DelayedControls::applyControls);
+
/**
* \todo Dynamically assign ImgU and output devices to each
* stream and camera; as of now, limit support to two cameras
@@ -933,6 +996,34 @@ int PipelineHandlerIPU3::registerCameras()
return numCameras ? 0 : -ENODEV;
}
+int IPU3CameraData::loadIPA()
+{
+ ipa_ = IPAManager::createIPA(pipe_, 1, 1);
+ if (!ipa_)
+ return -ENOENT;
+
+ ipa_->queueFrameAction.connect(this, &IPU3CameraData::queueFrameAction);
+
+ ipa_->init(IPASettings{});
+
+ return 0;
+}
+
+void IPU3CameraData::queueFrameAction([[maybe_unused]] unsigned int id,
+ const IPAOperationData &action)
+{
+ switch (action.operation) {
+ case IPU3_IPA_ACTION_SET_SENSOR_CONTROLS: {
+ const ControlList &controls = action.controls[0];
+ delayedCtrls_->push(controls);
+ break;
+ }
+ default:
+ LOG(IPU3, Error) << "Unknown action " << action.operation;
+ break;
+ }
+}
+
/* -----------------------------------------------------------------------------
* Buffer Ready slots
*/