summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacopo Mondi <jacopo.mondi@ideasonboard.com>2025-01-02 16:07:52 +0100
committerJacopo Mondi <jacopo.mondi@ideasonboard.com>2025-01-03 12:33:44 +0100
commitf1fd445d619be6ea5baf40d784f6c797e0055f5b (patch)
treef4509af8ad0c96f835c75f165c7785e41536e399
parent35ed4b91291d9f3d08e4b51acfb51163e65df8f8 (diff)
libcamera: introduce rcar-gen4 supportrcar-gen4
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
-rw-r--r--meson_options.txt1
-rw-r--r--src/libcamera/pipeline/rcar-gen4/meson.build5
-rw-r--r--src/libcamera/pipeline/rcar-gen4/rcar-gen4.cpp240
3 files changed, 246 insertions, 0 deletions
diff --git a/meson_options.txt b/meson_options.txt
index 1dc3b4cd..2977aaff 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -49,6 +49,7 @@ option('pipelines',
'imx8-isi',
'ipu3',
'mali-c55',
+ 'rcar-gen4',
'rkisp1',
'rpi/vc4',
'simple',
diff --git a/src/libcamera/pipeline/rcar-gen4/meson.build b/src/libcamera/pipeline/rcar-gen4/meson.build
new file mode 100644
index 00000000..1d514677
--- /dev/null
+++ b/src/libcamera/pipeline/rcar-gen4/meson.build
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: CC0-1.0
+
+libcamera_internal_sources += files([
+ 'rcar-gen4.cpp',
+])
diff --git a/src/libcamera/pipeline/rcar-gen4/rcar-gen4.cpp b/src/libcamera/pipeline/rcar-gen4/rcar-gen4.cpp
new file mode 100644
index 00000000..9e5b4419
--- /dev/null
+++ b/src/libcamera/pipeline/rcar-gen4/rcar-gen4.cpp
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Ideas On Board Oy
+ *
+ * Pipeline handler for Renesas R-Car Gen4
+ */
+
+#include <memory>
+#include <string>
+
+#include <libcamera/stream.h>
+
+#include "libcamera/internal/camera.h"
+#include "libcamera/internal/device_enumerator.h"
+#include "libcamera/internal/media_device.h"
+#include "libcamera/internal/pipeline_handler.h"
+#include "libcamera/internal/v4l2_subdevice.h"
+#include "libcamera/internal/v4l2_videodevice.h"
+
+namespace libcamera {
+
+LOG_DEFINE_CATEGORY(RCar4)
+
+class RCar4CameraData : public Camera::Private
+{
+public:
+ RCar4CameraData(PipelineHandler *pipe)
+ : Camera::Private(pipe)
+ {
+ }
+
+ Stream humanVision;
+ Stream machineVision;
+};
+
+struct RCar4CameraPipe {
+ MediaDevice *mdev;
+ std::unique_ptr<V4L2Subdevice> ispCore;
+ std::unique_ptr<V4L2Subdevice> ispCS;
+ std::unique_ptr<V4L2Subdevice> csi2Rx;
+ std::unique_ptr<V4L2Subdevice> sensor;
+ std::unique_ptr<V4L2VideoDevice> params;
+ std::unique_ptr<V4L2VideoDevice> stats;
+ std::unique_ptr<V4L2VideoDevice> exposure1;
+ std::unique_ptr<V4L2VideoDevice> exposure2;
+ std::unique_ptr<V4L2VideoDevice> machineVision;
+ std::unique_ptr<V4L2VideoDevice> humanVision;
+};
+
+class PipelineHandlerRCar4 : public PipelineHandler
+{
+public:
+ PipelineHandlerRCar4(CameraManager *manager);
+
+ std::unique_ptr<CameraConfiguration> generateConfiguration(Camera *camera,
+ Span<const StreamRole> roles) override;
+ int configure(Camera *camera, CameraConfiguration *config) override;
+
+ int exportFrameBuffers(Camera *camera, Stream *stream,
+ std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
+
+ int start(Camera *camera, const ControlList *controls) override;
+ void stopDevice(Camera *camera) override;
+
+ int queueRequestDevice(Camera *camera, Request *request) override;
+
+ bool match(DeviceEnumerator *enumerator) override;
+
+private:
+ int createCamera(MediaDevice *mdev, std::string &pipeId);
+
+ std::vector<RCar4CameraPipe> pipes_;
+};
+
+PipelineHandlerRCar4::PipelineHandlerRCar4(CameraManager *manager)
+ : PipelineHandler(manager)
+{
+}
+
+std::unique_ptr<CameraConfiguration>
+PipelineHandlerRCar4::generateConfiguration([[maybe_unused]] Camera *camera,
+ [[maybe_unused]] Span<const StreamRole> roles)
+{
+ return {};
+}
+
+int PipelineHandlerRCar4::configure([[maybe_unused]] Camera *camera,
+ [[maybe_unused]] CameraConfiguration *c)
+{
+ return 0;
+}
+
+int PipelineHandlerRCar4::exportFrameBuffers([[maybe_unused]] Camera *camera,
+ [[maybe_unused]] Stream *stream,
+ [[maybe_unused]] std::vector<std::unique_ptr<FrameBuffer>> *buffers)
+{
+ return 0;
+}
+
+int PipelineHandlerRCar4::start([[maybe_unused]] Camera *camera,
+ [[maybe_unused]] const ControlList *controls)
+{
+ return 0;
+}
+
+void PipelineHandlerRCar4::stopDevice([[maybe_unused]] Camera *camera)
+{
+}
+
+int PipelineHandlerRCar4::queueRequestDevice([[maybe_unused]] Camera *camera,
+ [[maybe_unused]] Request *request)
+{
+ return 0;
+}
+
+int PipelineHandlerRCar4::createCamera(MediaDevice *mdev, std::string &pipeId)
+{
+ RCar4CameraPipe pipe{};
+
+ pipe.mdev = mdev;
+ pipe.ispCS = V4L2Subdevice::fromEntityName(mdev, pipeId);
+ if (!pipe.ispCS) {
+ LOG(RCar4, Error) << "Failed to find " << pipeId;
+ return -EINVAL;
+ }
+
+ pipe.ispCore = V4L2Subdevice::fromEntityName(mdev, pipeId + " core");
+ if (!pipe.ispCore) {
+ LOG(RCar4, Error) << "Failed to find " << pipeId + " core";
+ return -EINVAL;
+ }
+
+ /* Create the ISP video devices. */
+ const MediaEntity *ispEntity = pipe.ispCore->entity();
+ const MediaPad *pad = ispEntity->getPadByIndex(0);
+ const MediaPad *vdevPad = pad->links()[0]->source();
+ pipe.exposure1 = V4L2VideoDevice::fromEntityName(mdev,
+ vdevPad->entity()->name());
+
+ pad = ispEntity->getPadByIndex(1);
+ vdevPad = pad->links()[0]->source();
+ pipe.exposure2 = V4L2VideoDevice::fromEntityName(mdev,
+ vdevPad->entity()->name());
+
+ pad = ispEntity->getPadByIndex(2);
+ vdevPad = pad->links()[0]->source();
+ pipe.params = V4L2VideoDevice::fromEntityName(mdev,
+ vdevPad->entity()->name());
+
+ pad = ispEntity->getPadByIndex(3);
+ vdevPad = pad->links()[0]->sink();
+ pipe.stats = V4L2VideoDevice::fromEntityName(mdev,
+ vdevPad->entity()->name());
+
+ pad = ispEntity->getPadByIndex(4);
+ vdevPad = pad->links()[0]->sink();
+ pipe.humanVision = V4L2VideoDevice::fromEntityName(mdev,
+ vdevPad->entity()->name());
+
+ pad = ispEntity->getPadByIndex(5);
+ vdevPad = pad->links()[0]->sink();
+ pipe.machineVision = V4L2VideoDevice::fromEntityName(mdev,
+ vdevPad->entity()->name());
+
+ if (!pipe.exposure1 || !pipe.exposure2 || !pipe.params || !pipe.stats ||
+ !pipe.humanVision || !pipe.machineVision) {
+ LOG(RCar4, Error) << "Unable to find ISP components";
+ return -ENODEV;
+ }
+
+ /*
+ * Walk the ispCS sink link to get to the csi-2 Rx and from
+ * there create a camera.
+ */
+ const MediaEntity *entity = pipe.ispCS->entity();
+ pad = entity->getPadByIndex(0);
+ const MediaPad *source = pad->links()[0]->source();
+ pipe.csi2Rx = V4L2Subdevice::fromEntityName(mdev, source->entity()->name());
+ if (!pipe.csi2Rx) {
+ LOG(RCar4, Error) << "Failed to find CSI-2 Rx entity";
+ return -EINVAL;
+ }
+
+ entity = pipe.csi2Rx->entity();
+ pad = entity->getPadByIndex(0);
+ source = pad->links()[0]->source();
+ pipe.sensor = V4L2Subdevice::fromEntityName(mdev, source->entity()->name());
+ if (!pipe.sensor) {
+ LOG(RCar4, Error) << "Failed to find sensor entity";
+ return -EINVAL;
+ }
+
+ std::unique_ptr<RCar4CameraData> data =
+ std::make_unique<RCar4CameraData>(this);
+
+ std::set<Stream *> streams{
+ &data->humanVision,
+ &data->machineVision,
+ };
+
+ const std::string id = pipe.sensor->entity()->name();
+ std::shared_ptr<Camera> camera =
+ Camera::create(std::move(data), id, streams);
+ registerCamera(std::move(camera));
+
+ return 0;
+}
+
+bool PipelineHandlerRCar4::match(DeviceEnumerator *enumerator)
+{
+ DeviceMatch dm("rcar_vin");
+
+ MediaDevice *media = acquireMediaDevice(enumerator, dm);
+ if (!media)
+ return false;
+
+ /*
+ * Walk the entities in the media graph to identify the required
+ * components.
+ */
+ for (const MediaEntity *entity : media->entities()) {
+ /* Identify the ISP core entries (part of the same media graph). */
+ if (entity->name().substr(0, 8) == "rcar_isp" &&
+ entity->name().rfind("core") != std::string::npos) {
+ /*
+ * Isolate the unit address that identifies one ISP
+ * instance. pipeId will look like
+ * 'rcar_isp fed00000.isp'.
+ */
+ std::string pipeId = entity->name().substr(0, 21);
+ createCamera(media, pipeId);
+ }
+ }
+
+ return false;
+}
+
+REGISTER_PIPELINE_HANDLER(PipelineHandlerRCar4, "rcar-gen4")
+
+} /* namespace libcamera */