[libcamera-devel,24/27] libcamera: pipeline: ipu3: Implement capture support

Message ID 20190206060818.13907-25-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • Capture frames throught requests
Related show

Commit Message

Laurent Pinchart Feb. 6, 2019, 6:08 a.m. UTC
From: Jacopo Mondi <jacopo@jmondi.org>

Replace the buffer allocation, capture start/stop and request queue
stubs with real implementations.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/libcamera/pipeline/ipu3/ipu3.cpp | 123 +++++++++++++++++++++++++--
 1 file changed, 114 insertions(+), 9 deletions(-)

Patch

diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 9629057a1b2f..34b03995ae31 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -9,6 +9,7 @@ 
 #include <vector>
 
 #include <libcamera/camera.h>
+#include <libcamera/request.h>
 #include <libcamera/stream.h>
 
 #include "device_enumerator.h"
@@ -97,12 +98,23 @@  PipelineHandlerIPU3::streamConfiguration(Camera *camera,
 					 std::vector<Stream *> &streams)
 {
 	IPU3CameraData *data = cameraData(camera);
-
 	std::map<Stream *, StreamConfiguration> configs;
+	V4L2SubdeviceFormat format = {};
 
-	StreamConfiguration config{};
+	/*
+	 * FIXME: As of now, return the image format reported by the sensor.
+	 * In future good defaults should be provided for each stream.
+	 */
+	if (data->sensor_->getFormat(0, &format)) {
+		LOG(IPU3, Error) << "Failed to create stream configurations";
+		return configs;
+	}
 
-	LOG(IPU3, Info) << "TODO: Return a good default format";
+	StreamConfiguration config = {};
+	config.width = format.width;
+	config.height = format.height;
+	config.pixelFormat = V4L2_PIX_FMT_IPU3_SGRBG10;
+	config.bufferCount = 4;
 
 	configs[&data->stream_] = config;
 
@@ -113,38 +125,131 @@  int PipelineHandlerIPU3::configureStreams(Camera *camera,
 					  std::map<Stream *, StreamConfiguration> &config)
 {
 	IPU3CameraData *data = cameraData(camera);
-
 	StreamConfiguration *cfg = &config[&data->stream_];
+	V4L2Subdevice *sensor = data->sensor_;
+	V4L2Subdevice *csi2 = data->csi2_;
+	V4L2Device *cio2 = data->cio2_;
+	V4L2SubdeviceFormat subdevFormat = {};
+	V4L2DeviceFormat devFormat = {};
+	int ret;
 
-	LOG(IPU3, Info) << "TODO: Configure the camera for resolution "
-			<< cfg->width << "x" << cfg->height;
+	/*
+	 * FIXME: as of now, the format gets applied to the sensor and is
+	 * propagated along the pipeline. It should instead be applied on the
+	 * capture device and the sensor format calculated accordingly.
+	 */
+
+	ret = sensor->getFormat(0, &subdevFormat);
+	if (ret)
+		return ret;
+
+	subdevFormat.width = cfg->width;
+	subdevFormat.height = cfg->height;
+	ret = sensor->setFormat(0, &subdevFormat);
+	if (ret)
+		return ret;
+
+	/* Return error if the requested format cannot be applied to sensor. */
+	if (subdevFormat.width != cfg->width ||
+	    subdevFormat.height != cfg->height) {
+		LOG(IPU3, Error)
+			<< "Failed to apply image format "
+			<< subdevFormat.width << "x" << subdevFormat.height
+			<< " - got: " << cfg->width << "x" << cfg->height;
+		return -EINVAL;
+	}
+
+	ret = csi2->setFormat(0, &subdevFormat);
+	if (ret)
+		return ret;
+
+	ret = cio2->getFormat(&devFormat);
+	if (ret)
+		return ret;
+
+	devFormat.width = subdevFormat.width;
+	devFormat.height = subdevFormat.height;
+	devFormat.fourcc = cfg->pixelFormat;
+
+	ret = cio2->setFormat(&devFormat);
+	if (ret)
+		return ret;
+
+	LOG(IPU3, Info) << cio2->driverName() << ": "
+			<< devFormat.width << "x" << devFormat.height
+			<< "- 0x" << std::hex << devFormat.fourcc << " planes: "
+			<< devFormat.planes;
 
 	return 0;
 }
 
 int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream)
 {
-	return -ENOTRECOVERABLE;
+	IPU3CameraData *data = cameraData(camera);
+	const StreamConfiguration &cfg = stream->configuration();
+
+	if (!cfg.bufferCount)
+		return -EINVAL;
+
+	int ret = data->cio2_->exportBuffers(cfg.bufferCount,
+					     &stream->bufferPool());
+	if (ret) {
+		LOG(IPU3, Error) << "Failed to request memory";
+		return ret;
+	}
+
+	return 0;
 }
 
 int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream)
 {
+	IPU3CameraData *data = cameraData(camera);
+
+	int ret = data->cio2_->releaseBuffers();
+	if (ret) {
+		LOG(IPU3, Error) << "Failed to release memory";
+		return ret;
+	}
+
 	return 0;
 }
 
 int PipelineHandlerIPU3::start(const Camera *camera)
 {
-	LOG(IPU3, Error) << "TODO: start camera";
+	IPU3CameraData *data = cameraData(camera);
+	int ret;
+
+	ret = data->cio2_->streamOn();
+	if (ret) {
+		LOG(IPU3, Info) << "Failed to start camera " << camera->name();
+		return ret;
+	}
+
 	return 0;
 }
 
 void PipelineHandlerIPU3::stop(const Camera *camera)
 {
-	LOG(IPU3, Error) << "TODO: stop camera";
+	IPU3CameraData *data = cameraData(camera);
+
+	if (data->cio2_->streamOff())
+		LOG(IPU3, Info) << "Failed to stop camera " << camera->name();
 }
 
 int PipelineHandlerIPU3::queueRequest(const Camera *camera, Request *request)
 {
+	IPU3CameraData *data = cameraData(camera);
+	Stream *stream = &data->stream_;
+
+	Buffer *buffer = request->findBuffer(stream);
+	if (!buffer) {
+		LOG(IPU3, Error)
+			<< "Attempt to queue request with invalid stream";
+		return -ENOENT;
+	}
+
+	data->cio2_->queueBuffer(buffer);
+
 	return 0;
 }