[PATCH/RFC,29/32] pipeline: raspberrypi: vc4: Configure format on Unicam subdev
diff mbox series

Message ID 20240301212121.9072-30-laurent.pinchart@ideasonboard.com
State RFC
Headers show
Series
  • libcamera: Support the upstream Unicam driver
Related show

Commit Message

Laurent Pinchart March 1, 2024, 9:21 p.m. UTC
The mainline Unicam driver creates a V4L2 subdevice, which needs to be
configured. Create and open a corresponding V4L2Subdevice instance and
configure the format on its sink pad in the platformConfigure()
function.

Presence of the Unicam subdev is required, to avoid extra complexity.
This drops support for the driver from the Raspberry Pi downstream
kernel. Users are expected to update their kernel to use the mainline
Unicam driver.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/libcamera/pipeline/rpi/vc4/vc4.cpp | 78 ++++++++++++++++++++++----
 1 file changed, 68 insertions(+), 10 deletions(-)

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
index da925ba5f793..81e0bc1b8f7a 100644
--- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
+++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
@@ -5,6 +5,8 @@ 
  * vc4.cpp - Pipeline handler for VC4-based Raspberry Pi devices
  */
 
+#include <memory>
+
 #include <linux/bcm2835-isp.h>
 #include <linux/v4l2-controls.h>
 #include <linux/videodev2.h>
@@ -12,6 +14,7 @@ 
 #include <libcamera/formats.h>
 
 #include "libcamera/internal/device_enumerator.h"
+#include "libcamera/internal/v4l2_subdevice.h"
 
 #include "../common/pipeline_base.h"
 #include "../common/rpi_stream.h"
@@ -32,6 +35,10 @@  namespace {
 enum class Unicam : unsigned int { Image, Embedded };
 enum class Isp : unsigned int { Input, Output0, Output1, Stats };
 
+static constexpr unsigned int kUnicamSinkPad = 0;
+static constexpr unsigned int kUnicamSourceImagePad = 1;
+static constexpr unsigned int kUnicamSourceMetadataPad = 2;
+
 } /* namespace */
 
 class Vc4CameraData final : public RPi::CameraData
@@ -82,6 +89,8 @@  public:
 	void setIspControls(const ControlList &controls);
 	void setCameraTimeout(uint32_t maxFrameLengthMs);
 
+	std::unique_ptr<V4L2Subdevice> unicamSubdev_;
+
 	/* Array of Unicam and ISP device streams and associated buffers/streams. */
 	RPi::Device<Unicam, 2> unicam_;
 	RPi::Device<Isp, 4> isp_;
@@ -310,6 +319,7 @@  int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &camer
 	if (!data->dmaHeap_.isValid())
 		return -ENOMEM;
 
+	MediaEntity *unicamSubdev = unicam->getEntityByName("unicam");
 	MediaEntity *unicamImage = unicam->getEntityByName("unicam-image");
 	MediaEntity *unicamEmbedded = unicam->getEntityByName("unicam-embedded");
 	MediaEntity *ispOutput0 = isp->getEntityByName("bcm2835-isp0-output0");
@@ -321,7 +331,13 @@  int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &camer
 	    !ispOutput0 || !ispCapture1 || !ispCapture2 || !ispCapture3)
 		return -ENOENT;
 
-	/* Create the unicam video streams. */
+	if (!unicamSubdev) {
+		LOG(RPI, Error) << "Downstream Unicam driver not supported, please update your kernel!";
+		return -EINVAL;
+	}
+
+	/* Create the unicam subdev and video streams. */
+	data->unicamSubdev_ = std::make_unique<V4L2Subdevice>(unicamSubdev);
 	data->unicam_[Unicam::Image] = RPi::Stream("Unicam Image", unicamImage);
 	data->unicam_[Unicam::Embedded] = RPi::Stream("Unicam Embedded", unicamEmbedded);
 
@@ -350,6 +366,10 @@  int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &camer
 	 * The below grouping is just for convenience so that we can easily
 	 * iterate over all streams in one go.
 	 */
+	int ret = data->unicamSubdev_->open();
+	if (ret < 0)
+		return ret;
+
 	data->streams_.push_back(&data->unicam_[Unicam::Image]);
 	if (data->sensorMetadata_)
 		data->streams_.push_back(&data->unicam_[Unicam::Embedded]);
@@ -358,16 +378,11 @@  int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &camer
 		data->streams_.push_back(&stream);
 
 	for (auto stream : data->streams_) {
-		int ret = stream->dev()->open();
+		ret = stream->dev()->open();
 		if (ret)
 			return ret;
 	}
 
-	if (!data->unicam_[Unicam::Image].dev()->caps().hasMediaController()) {
-		LOG(RPI, Error) << "Unicam driver does not use the MediaController, please update your kernel!";
-		return -EINVAL;
-	}
-
 	/* Write up all the IPA connections. */
 	data->ipa_->processStatsComplete.connect(data, &Vc4CameraData::processStatsComplete);
 	data->ipa_->prepareIspComplete.connect(data, &Vc4CameraData::prepareIspComplete);
@@ -530,7 +545,50 @@  int Vc4CameraData::platformPipelineConfigure(const std::unique_ptr<YamlObject> &
 int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfig)
 {
 	/*
-	 * 1. Configure the Unicam video devices.
+	 * 1. Configure the Unicam subdev.
+	 *
+	 * Start by setting up routes, and then set the formats on the sink pad
+	 * streams. They will be automatically propagated to the source pads by
+	 * the kernel.
+	 */
+
+	const V4L2Subdevice::Stream imageStream{
+		kUnicamSinkPad,
+		sensor_->imageStream().stream
+	};
+	const V4L2Subdevice::Stream embeddedDataStream{
+		kUnicamSinkPad,
+		sensor_->embeddedDataStream().value_or(V4L2Subdevice::Stream{}).stream
+	};
+
+	V4L2Subdevice::Routing routing;
+
+	routing.emplace_back(imageStream, V4L2Subdevice::Stream{ kUnicamSourceImagePad, 0 },
+			     V4L2_SUBDEV_ROUTE_FL_ACTIVE);
+
+	if (sensorMetadata_)
+		routing.emplace_back(embeddedDataStream,
+				     V4L2Subdevice::Stream{ kUnicamSourceMetadataPad, 0 },
+				     V4L2_SUBDEV_ROUTE_FL_ACTIVE);
+
+	int ret = unicamSubdev_->setRouting(&routing);
+	if (ret)
+		return ret;
+
+	V4L2SubdeviceFormat subdevFormat = rpiConfig->sensorFormat_;
+	ret = unicamSubdev_->setFormat(imageStream, &subdevFormat);
+	if (ret)
+		return ret;
+
+	if (sensorMetadata_) {
+		subdevFormat = sensor_->embeddedDataFormat();
+		ret = unicamSubdev_->setFormat(embeddedDataStream, &subdevFormat);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * 2. Configure the Unicam video devices.
 	 */
 
 	V4L2VideoDevice *unicam = unicam_[Unicam::Image].dev();
@@ -553,7 +611,7 @@  int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfi
 								     BayerFormat::Packing::CSI2);
 	}
 
-	int ret = unicam->setFormat(&unicamFormat);
+	ret = unicam->setFormat(&unicamFormat);
 	if (ret)
 		return ret;
 
@@ -581,7 +639,7 @@  int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfi
 	}
 
 	/*
-	 * 2. Configure the ISP.
+	 * 3. Configure the ISP.
 	 */
 
 	ret = isp_[Isp::Input].dev()->setFormat(&unicamFormat);