@@ -44,6 +44,8 @@
#include "libcamera/internal/v4l2_subdevice.h"
#include "libcamera/internal/v4l2_videodevice.h"
+#include "rzg2l-cru.h"
+
namespace {
bool isFormatRaw(const libcamera::PixelFormat &pixFmt)
@@ -105,7 +107,12 @@ public:
std::unique_ptr<V4L2Subdevice> csi2_;
std::unique_ptr<CameraSensor> sensor_;
};
- using CameraType = std::variant<Tpg, Inline>;
+
+ struct Memory {
+ std::unique_ptr<RZG2LCRU> cru_;
+ };
+
+ using CameraType = std::variant<Tpg, Inline, Memory>;
MaliC55CameraData(PipelineHandler *pipe)
: Camera::Private(pipe)
@@ -116,6 +123,7 @@ public:
int initTpg(MediaEntity *entity);
int initInline(MediaEntity *entity);
+ int initMemory(MediaDevice *cruMedia);
std::vector<Size> sizes(unsigned int mbusCode) const
{
@@ -125,6 +133,9 @@ public:
},
[&](const Inline &in) -> std::vector<Size> {
return in.sensor_->sizes(mbusCode);
+ },
+ [&](const Memory &mem) -> std::vector<Size> {
+ return mem.cru_->sizes();
}
}, input_);
}
@@ -137,6 +148,9 @@ public:
},
[&](const Inline &in) -> V4L2Subdevice * {
return in.sensor_->device();
+ },
+ [&](const Memory &mem) -> V4L2Subdevice * {
+ return mem.cru_->sensor()->device();
}
}, input_);
}
@@ -150,6 +164,9 @@ public:
},
[&](const Inline &in) -> CameraSensor * {
return in.sensor_.get();
+ },
+ [&](const Memory &mem) -> CameraSensor * {
+ return mem.cru_->sensor();
}
}, input_);
}
@@ -163,6 +180,9 @@ public:
},
[&](const Inline &in) -> V4L2Subdevice * {
return in.csi2_.get();
+ },
+ [&](const Memory &mem) -> V4L2Subdevice * {
+ return mem.cru_->csi2();
}
}, input_);
}
@@ -175,10 +195,26 @@ public:
},
[&](const Inline &in) -> Size {
return in.sensor_->resolution();
+ },
+ [&](const Memory &mem) -> Size {
+ return mem.cru_->resolution();
}
}, input_);
}
+ RZG2LCRU *cru() const
+ {
+ return std::visit(utils::overloaded{
+ [&](auto &) -> RZG2LCRU * {
+ ASSERT(false);
+ return nullptr;
+ },
+ [&](const Memory &mem) -> RZG2LCRU * {
+ return mem.cru_.get();
+ },
+ }, input_);
+ }
+
int pixfmtToMbusCode(const PixelFormat &pixFmt) const;
const PixelFormat &bestRawFormat() const;
@@ -258,6 +294,21 @@ int MaliC55CameraData::initInline(MediaEntity *sensor)
return 0;
}
+int MaliC55CameraData::initMemory(MediaDevice *cruMedia)
+{
+ Memory mem;
+
+ mem.cru_ = std::make_unique<RZG2LCRU>();
+
+ int ret = mem.cru_->init(cruMedia);
+ if (ret)
+ return ret;
+
+ input_.emplace<Memory>(std::move(mem));
+
+ return 0;
+}
+
std::vector<Size> MaliC55CameraData::Tpg::sizes(unsigned int mbusCode) const
{
V4L2Subdevice::Formats formats = sd_->formats(0);
@@ -738,11 +789,15 @@ private:
const std::string &name);
bool registerTPGCamera(MediaLink *link);
bool registerSensorCamera(MediaLink *link);
+ bool registerMemoryInputCamera();
std::shared_ptr<MediaDevice> media_;
+ std::shared_ptr<MediaDevice> cruMedia_;
std::unique_ptr<V4L2Subdevice> isp_;
std::unique_ptr<V4L2VideoDevice> stats_;
std::unique_ptr<V4L2VideoDevice> params_;
+ std::unique_ptr<V4L2Subdevice> ivcSd_;
+ std::unique_ptr<V4L2VideoDevice> ivc_;
std::vector<std::unique_ptr<FrameBuffer>> statsBuffers_;
std::queue<FrameBuffer *> availableStatsBuffers_;
@@ -993,6 +1048,9 @@ int PipelineHandlerMaliC55::configure(Camera *camera,
const MediaEntity *csi2Entity = in.csi2_->entity();
return csi2Entity->getPadByIndex(1)->links()[0]->setEnabled(true);
},
+ [](MaliC55CameraData::Memory &) {
+ return 0;
+ }
}, data->input_);
if (ret)
return ret;
@@ -1018,6 +1076,9 @@ int PipelineHandlerMaliC55::configure(Camera *camera,
return data->csi2()->getFormat(1, &subdevFormat);
},
+ [](MaliC55CameraData::Memory &) {
+ return 0;
+ }
}, data->input_);
if (ret)
return ret;
@@ -1691,6 +1752,34 @@ bool PipelineHandlerMaliC55::registerSensorCamera(MediaLink *ispLink)
return true;
}
+bool PipelineHandlerMaliC55::registerMemoryInputCamera()
+{
+ std::unique_ptr<MaliC55CameraData> data =
+ std::make_unique<MaliC55CameraData>(this);
+
+ int ret = data->initMemory(cruMedia_.get());
+ if (ret)
+ return false;
+
+ CameraSensor *sensor = data->sensor();
+ data->properties_ = sensor->properties();
+
+ const CameraSensorProperties::SensorDelays &delays = sensor->sensorDelays();
+ std::unordered_map<uint32_t, DelayedControls::ControlParams> params = {
+ { V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },
+ { V4L2_CID_EXPOSURE, { delays.exposureDelay, false } },
+ };
+
+ data->delayedCtrls_ =
+ std::make_unique<DelayedControls>(sensor->device(), params);
+ isp_->frameStart.connect(data->delayedCtrls_.get(),
+ &DelayedControls::applyControls);
+
+ ivc_->bufferReady.connect(data->cru(), &RZG2LCRU::cruReturnBuffer);
+
+ return registerMaliCamera(std::move(data), sensor->device()->entity()->name());
+}
+
bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator)
{
const MediaPad *ispSink;
@@ -1700,14 +1789,14 @@ bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator)
* The TPG and the downscale pipe are both optional blocks and may not
* be fitted.
*/
- DeviceMatch dm("mali-c55");
- dm.add("mali-c55 isp");
- dm.add("mali-c55 resizer fr");
- dm.add("mali-c55 fr");
- dm.add("mali-c55 3a stats");
- dm.add("mali-c55 3a params");
-
- media_ = acquireMediaDevice(enumerator, dm);
+ DeviceMatch c55_dm("mali-c55");
+ c55_dm.add("mali-c55 isp");
+ c55_dm.add("mali-c55 resizer fr");
+ c55_dm.add("mali-c55 fr");
+ c55_dm.add("mali-c55 3a stats");
+ c55_dm.add("mali-c55 3a params");
+
+ media_ = acquireMediaDevice(enumerator, c55_dm);
if (!media_)
return false;
@@ -1767,6 +1856,25 @@ bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator)
stats_->bufferReady.connect(this, &PipelineHandlerMaliC55::statsBufferReady);
params_->bufferReady.connect(this, &PipelineHandlerMaliC55::paramsBufferReady);
+ /*
+ * We also need to search for the rzg2l-cru CSI-2 receiver. If we find
+ * that then we need to work in memory input mode instead of the inline
+ * mode. The absence of this match is not necessarily a failure at this
+ * point...it depends on the media links that we investigate momentarily.
+ *
+ * This is a bit hacky, because there could be multiple of these media
+ * devices and we're just taking the first. We need modular pipelines to
+ * properly solve the issue.
+ */
+ static const std::regex cruCsi2Regex("csi-[0-9a-f]{8}.csi2");
+ static const std::regex cruIpRegex("cru-ip-[0-9a-f]{8}.cru[0-9]");
+
+ DeviceMatch cruDm("rzg2l_cru");
+ cruDm.add(cruCsi2Regex);
+ cruDm.add(cruIpRegex);
+ cruDm.add("CRU output");
+ cruMedia_ = acquireMediaDevice(enumerator, cruDm);
+
ispSink = isp_->entity()->getPadByIndex(0);
if (!ispSink || ispSink->links().empty()) {
LOG(MaliC55, Error) << "ISP sink pad error";
@@ -1780,13 +1888,6 @@ bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator)
* MEDIA_ENT_F_CAM_SENSOR - The test pattern generator
* MEDIA_ENT_F_VID_IF_BRIDGE - A CSI-2 receiver
* MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER - An input device
- *
- * The last one will be unsupported for now. The TPG is relatively easy,
- * we just register a Camera for it. If we have a CSI-2 receiver we need
- * to check its sink pad and register Cameras for anything connected to
- * it (probably...there are some complex situations in which that might
- * not be true but let's pretend they don't exist until we come across
- * them)
*/
bool registered;
for (MediaLink *link : ispSink->links()) {
@@ -1806,7 +1907,23 @@ bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator)
break;
case MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER:
- LOG(MaliC55, Warning) << "Memory input not yet supported";
+ if (!cruMedia_)
+ return false;
+
+ ivcSd_ = V4L2Subdevice::fromEntityName(media_.get(),
+ "rzv2h ivc block");
+ if (ivcSd_->open() < 0)
+ return false;
+
+ ivc_ = V4L2VideoDevice::fromEntityName(media_.get(),
+ "rzv2h-ivc");
+ if (ivc_->open() < 0)
+ return false;
+
+ registered = registerMemoryInputCamera();
+ if (!registered)
+ return registered;
+
break;
default:
LOG(MaliC55, Error) << "Unsupported entity function";