| Message ID | ae369612-0d35-47b9-8796-d3670bfd9086@gmx.de |
|---|---|
| State | Rejected |
| Headers | show |
| Series |
|
| Related | show |
Hi Christian, On Sun, May 17, 2026 at 12:38:52PM +0200, Christian Rauch wrote: > Dear all, > > A while ago (actually nearly a year to this date) I was asking about the > Raspberry Pi 5 support in upstream libcamera and Naush mentioned that > Raspberry Pi is using a workaround in the CFE kernel driver to make this > work. I assume that Naush was talking about the kernel module "rp1_cfe", > which is shipped with the workaround as "rp1_cfe_downstream" in > Raspberry Pi OS. > > Ubuntu 26.04 with its kernel "7.0.0-1010-raspi" ships the "rp1_cfe" > module with workaround as "rp1_cfe_downstream" too, and also patched > (patch attached) the upstream libcamera sources with a fix to detect the > camera when either of those kernel modules is loaded. > > Since the Raspberry Pi 5 support is still not available with upstream > libcamera and the "rp1_cfe" kernel module, and it seems it is going to > stay that way for a while, would you accept the attached patch to > replicate the behaviour in the Raspberry Pi libcamera fork? > > Given that the "rp1_cfe" module does not work with the upstream > "rpi/pisp" pipeline, how do you know that this pipeline handler is > actually working? Are you carrying custom patches on top of "rp1_cfe" to > make the upstream "rpi/pisp" work? Once the required features are merged > into upstream module "rp1_cfe", how do you know that the "rpi/pisp" > pipeline will still be compatible? I've just tested the latest libcamera release with the upstream kernel (v7.1-rc7). I had to add an overlay for the IMX219 camera module as that part is not upstream (and the downstream overlays are not compatible with upstream), but apart from that, the kernel is unmodified. The cam application runs fine and displays frames on the screen (which also means that HDMI output is working :-)). > Alternatively, couldn't the patches to the pipeline handler and kernel > modules be upstreamed in order to resolve this issue? There are currently two features missing upstream for the Raspberry Pi 5 camera pipeline: - Embedded data is not supported. This will require landing the "[PATCH v12 00/86] Generic line based metadata support, internal pads" ([1]) series. Lack of embedded data doesn't prevent the ISP from working. - Time-multiplexing of the ISP is not supported. This will require landing the "[PATCH v2 00/27] media: Add support for multi-context operations" ([2]) series. Lack of multi-context support prevents running multiple cameras concurrently. Once those series land, we will adapt the rp1-cfe driver (for [1]) and the pisp driver (for [2]) and the libcamera rpi5 pipeline handler. The two missing features are independent from each other, we can adaptat the kernel drivers and libcamera once one of the series lands without waiting for the other one. The plan is for the Raspberry Pi downstream kernel and libcamera to use the upstream APIs when they will be available. [1] https://lore.kernel.org/linux-media/20260409201501.975242-1-sakari.ailus@linux.intel.com/ [2] https://lore.kernel.org/linux-media/20250724-multicontext-mainline-2025-v2-0-c9b316773486@ideasonboard.com > Author: Pragyansh Chaturvedi <r41k0u@ubuntu.com> > Forwarded: not-needed > Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/libcamera/+bug/2110144 > Last-Update: 2026-02-18 > Description: Fix PiSP CFE entity match patterns > libcamera0.5 includes the PiSP drivers for Raspberry Pi. But > while registering the cameras, it is using different match > strings for CFE entities than what are present in Raspberry Pi's > fork of libcamera and the current device-tree overlays. This leads > to camera sensors not being detected on Raspberry Pi 5, which > used to work in libcamera0.4. > . > This indicates an upcoming change in these device-tree overlays, > as Raspberry Pi themselves upstreamed these changes to libcamera. > So this patch allows both the old and current match strings for > searching for CFE devices. This delta can be removed once our kernel > catches up and introduces the new strings. > > --- > --- a/include/libcamera/internal/device_enumerator.h > +++ b/include/libcamera/internal/device_enumerator.h > @@ -28,6 +28,8 @@ > > bool match(const MediaDevice *device) const; > > + void clear(); > + > private: > std::string driver_; > std::vector<std::string> entities_; > --- a/src/libcamera/device_enumerator.cpp > +++ b/src/libcamera/device_enumerator.cpp > @@ -157,6 +157,14 @@ > } > > /** > + * \brief Clear the entities search pattern vector > + */ > +void DeviceMatch::clear() > +{ > + entities_.clear(); > +} > + > +/** > * \class DeviceEnumerator > * \brief Enumerate, store and search media devices > * > --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp > +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp > @@ -888,7 +888,17 @@ > std::shared_ptr<MediaDevice> cfeDevice = acquireMediaDevice(enumerator, cfe); > > if (!cfeDevice) { > - LOG(RPI, Debug) << "Unable to acquire a CFE instance"; > + LOG(RPI, Debug) << "Trying old entity search patterns for CFE instance"; > + } > + > + cfe.clear(); > + cfe.add("rp1-cfe-fe_image0"); > + cfe.add("rp1-cfe-fe_stats"); > + cfe.add("rp1-cfe-fe_config"); > + cfeDevice = acquireMediaDevice(enumerator, cfe); > + > + if (!cfeDevice) { > + LOG(RPI, Debug) << "Unable to acquire CFE instance"; > break; > } > > @@ -1073,9 +1083,26 @@ > int ret; > > MediaEntity *cfeImage = cfe->getEntityByName("rp1-cfe-fe-image0"); > + if (!cfeImage) > + { > + cfeImage = cfe->getEntityByName("rp1-cfe-fe_image0"); > + } > MediaEntity *cfeEmbedded = cfe->getEntityByName("rp1-cfe-csi2-ch1"); > + if (!cfeEmbedded) > + { > + cfeEmbedded = cfe->getEntityByName("rp1-cfe-embedded"); > + } > MediaEntity *cfeStats = cfe->getEntityByName("rp1-cfe-fe-stats"); > + if (!cfeStats) > + { > + cfeStats = cfe->getEntityByName("rp1-cfe-fe_stats"); > + } > MediaEntity *cfeConfig = cfe->getEntityByName("rp1-cfe-fe-config"); > + if (!cfeConfig) > + { > + cfeConfig = cfe->getEntityByName("rp1-cfe-fe_config"); > + } > + > MediaEntity *ispInput = isp->getEntityByName("pispbe-input"); > MediaEntity *IpaPrepare = isp->getEntityByName("pispbe-config"); > MediaEntity *ispOutput0 = isp->getEntityByName("pispbe-output0"); > @@ -2144,8 +2171,9 @@ > int ret = 0; > > constexpr unsigned int csiVideoSinkPad = 0; > - constexpr unsigned int csiVideoSourcePad = 1; > - constexpr unsigned int csiMetaSourcePad = 2; > + constexpr unsigned int csiMetaSinkPad = 1; > + constexpr unsigned int csiVideoSourcePad = 4; > + constexpr unsigned int csiMetaSourcePad = 5; > > constexpr unsigned int feVideoSinkPad = 0; > constexpr unsigned int feConfigSinkPad = 1; > @@ -2156,48 +2184,29 @@ > const MediaEntity *csi2 = csi2Subdev_->entity(); > const MediaEntity *fe = feSubdev_->entity(); > > - for (MediaLink *link : csi2->pads()[csiVideoSourcePad]->links()) { > - if (link->sink()->entity()->name() == "rp1-cfe-csi2-ch0") > + for (MediaLink *link : csi2->getPadByIndex(csiVideoSourcePad)->links()) { > + if (link->sink()->entity()->name() == "rp1-cfe-csi2-ch0" || link->sink()->entity()->name() == "rp1-cfe-csi2_ch0") > link->setEnabled(false); > else if (link->sink()->entity()->name() == "pisp-fe") > link->setEnabled(true); > } > > - csi2->pads()[csiMetaSourcePad]->links()[0]->setEnabled(sensorMetadata_); > + csi2->getPadByIndex(csiMetaSourcePad)->links()[0]->setEnabled(sensorMetadata_); > > - fe->pads()[feConfigSinkPad]->links()[0]->setEnabled(true); > - fe->pads()[feVideo0SourcePad]->links()[0]->setEnabled(true); > - fe->pads()[feVideo1SourcePad]->links()[0]->setEnabled(false); > - fe->pads()[feStatsSourcePad]->links()[0]->setEnabled(true); > - > - const V4L2Subdevice::Stream imageStream{ > - csiVideoSinkPad, > - sensor_->imageStream().stream > - }; > - const V4L2Subdevice::Stream embeddedDataStream{ > - csiVideoSinkPad, > - sensor_->embeddedDataStream().value_or(V4L2Subdevice::Stream{}).stream > - }; > - > - V4L2Subdevice::Routing routing; > - routing.emplace_back(imageStream, V4L2Subdevice::Stream{ csiVideoSourcePad, 0 }, > - V4L2_SUBDEV_ROUTE_FL_ACTIVE); > - > - if (sensorMetadata_) > - routing.emplace_back(embeddedDataStream, > - V4L2Subdevice::Stream{ csiMetaSourcePad, 0 }, > - V4L2_SUBDEV_ROUTE_FL_ACTIVE); > - > - ret = csi2Subdev_->setRouting(&routing); > - if (ret) > - return ret; > + fe->getPadByIndex(feConfigSinkPad)->links()[0]->setEnabled(true); > + fe->getPadByIndex(feVideo0SourcePad)->links()[0]->setEnabled(true); > + fe->getPadByIndex(feVideo1SourcePad)->links()[0]->setEnabled(false); > + fe->getPadByIndex(feStatsSourcePad)->links()[0]->setEnabled(true); > > - ret = csi2Subdev_->setFormat(imageStream, &sensorFormat); > + ret = csi2Subdev_->setFormat(csiVideoSinkPad, &sensorFormat); > if (ret) > return ret; > > if (sensorMetadata_) { > - ret = csi2Subdev_->setFormat(embeddedDataStream, &embeddedFormat); > + ret = csi2Subdev_->setFormat(csiMetaSinkPad, &embeddedFormat); > + if (ret) > + return ret; > + ret = csi2Subdev_->setFormat(csiMetaSourcePad, &embeddedFormat); > if (ret) > return ret; > }
Author: Pragyansh Chaturvedi <r41k0u@ubuntu.com> Forwarded: not-needed Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/libcamera/+bug/2110144 Last-Update: 2026-02-18 Description: Fix PiSP CFE entity match patterns libcamera0.5 includes the PiSP drivers for Raspberry Pi. But while registering the cameras, it is using different match strings for CFE entities than what are present in Raspberry Pi's fork of libcamera and the current device-tree overlays. This leads to camera sensors not being detected on Raspberry Pi 5, which used to work in libcamera0.4. . This indicates an upcoming change in these device-tree overlays, as Raspberry Pi themselves upstreamed these changes to libcamera. So this patch allows both the old and current match strings for searching for CFE devices. This delta can be removed once our kernel catches up and introduces the new strings. --- --- a/include/libcamera/internal/device_enumerator.h +++ b/include/libcamera/internal/device_enumerator.h @@ -28,6 +28,8 @@ bool match(const MediaDevice *device) const; + void clear(); + private: std::string driver_; std::vector<std::string> entities_; --- a/src/libcamera/device_enumerator.cpp +++ b/src/libcamera/device_enumerator.cpp @@ -157,6 +157,14 @@ } /** + * \brief Clear the entities search pattern vector + */ +void DeviceMatch::clear() +{ + entities_.clear(); +} + +/** * \class DeviceEnumerator * \brief Enumerate, store and search media devices * --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp @@ -888,7 +888,17 @@ std::shared_ptr<MediaDevice> cfeDevice = acquireMediaDevice(enumerator, cfe); if (!cfeDevice) { - LOG(RPI, Debug) << "Unable to acquire a CFE instance"; + LOG(RPI, Debug) << "Trying old entity search patterns for CFE instance"; + } + + cfe.clear(); + cfe.add("rp1-cfe-fe_image0"); + cfe.add("rp1-cfe-fe_stats"); + cfe.add("rp1-cfe-fe_config"); + cfeDevice = acquireMediaDevice(enumerator, cfe); + + if (!cfeDevice) { + LOG(RPI, Debug) << "Unable to acquire CFE instance"; break; } @@ -1073,9 +1083,26 @@ int ret; MediaEntity *cfeImage = cfe->getEntityByName("rp1-cfe-fe-image0"); + if (!cfeImage) + { + cfeImage = cfe->getEntityByName("rp1-cfe-fe_image0"); + } MediaEntity *cfeEmbedded = cfe->getEntityByName("rp1-cfe-csi2-ch1"); + if (!cfeEmbedded) + { + cfeEmbedded = cfe->getEntityByName("rp1-cfe-embedded"); + } MediaEntity *cfeStats = cfe->getEntityByName("rp1-cfe-fe-stats"); + if (!cfeStats) + { + cfeStats = cfe->getEntityByName("rp1-cfe-fe_stats"); + } MediaEntity *cfeConfig = cfe->getEntityByName("rp1-cfe-fe-config"); + if (!cfeConfig) + { + cfeConfig = cfe->getEntityByName("rp1-cfe-fe_config"); + } + MediaEntity *ispInput = isp->getEntityByName("pispbe-input"); MediaEntity *IpaPrepare = isp->getEntityByName("pispbe-config"); MediaEntity *ispOutput0 = isp->getEntityByName("pispbe-output0"); @@ -2144,8 +2171,9 @@ int ret = 0; constexpr unsigned int csiVideoSinkPad = 0; - constexpr unsigned int csiVideoSourcePad = 1; - constexpr unsigned int csiMetaSourcePad = 2; + constexpr unsigned int csiMetaSinkPad = 1; + constexpr unsigned int csiVideoSourcePad = 4; + constexpr unsigned int csiMetaSourcePad = 5; constexpr unsigned int feVideoSinkPad = 0; constexpr unsigned int feConfigSinkPad = 1; @@ -2156,48 +2184,29 @@ const MediaEntity *csi2 = csi2Subdev_->entity(); const MediaEntity *fe = feSubdev_->entity(); - for (MediaLink *link : csi2->pads()[csiVideoSourcePad]->links()) { - if (link->sink()->entity()->name() == "rp1-cfe-csi2-ch0") + for (MediaLink *link : csi2->getPadByIndex(csiVideoSourcePad)->links()) { + if (link->sink()->entity()->name() == "rp1-cfe-csi2-ch0" || link->sink()->entity()->name() == "rp1-cfe-csi2_ch0") link->setEnabled(false); else if (link->sink()->entity()->name() == "pisp-fe") link->setEnabled(true); } - csi2->pads()[csiMetaSourcePad]->links()[0]->setEnabled(sensorMetadata_); + csi2->getPadByIndex(csiMetaSourcePad)->links()[0]->setEnabled(sensorMetadata_); - fe->pads()[feConfigSinkPad]->links()[0]->setEnabled(true); - fe->pads()[feVideo0SourcePad]->links()[0]->setEnabled(true); - fe->pads()[feVideo1SourcePad]->links()[0]->setEnabled(false); - fe->pads()[feStatsSourcePad]->links()[0]->setEnabled(true); - - const V4L2Subdevice::Stream imageStream{ - csiVideoSinkPad, - sensor_->imageStream().stream - }; - const V4L2Subdevice::Stream embeddedDataStream{ - csiVideoSinkPad, - sensor_->embeddedDataStream().value_or(V4L2Subdevice::Stream{}).stream - }; - - V4L2Subdevice::Routing routing; - routing.emplace_back(imageStream, V4L2Subdevice::Stream{ csiVideoSourcePad, 0 }, - V4L2_SUBDEV_ROUTE_FL_ACTIVE); - - if (sensorMetadata_) - routing.emplace_back(embeddedDataStream, - V4L2Subdevice::Stream{ csiMetaSourcePad, 0 }, - V4L2_SUBDEV_ROUTE_FL_ACTIVE); - - ret = csi2Subdev_->setRouting(&routing); - if (ret) - return ret; + fe->getPadByIndex(feConfigSinkPad)->links()[0]->setEnabled(true); + fe->getPadByIndex(feVideo0SourcePad)->links()[0]->setEnabled(true); + fe->getPadByIndex(feVideo1SourcePad)->links()[0]->setEnabled(false); + fe->getPadByIndex(feStatsSourcePad)->links()[0]->setEnabled(true); - ret = csi2Subdev_->setFormat(imageStream, &sensorFormat); + ret = csi2Subdev_->setFormat(csiVideoSinkPad, &sensorFormat); if (ret) return ret; if (sensorMetadata_) { - ret = csi2Subdev_->setFormat(embeddedDataStream, &embeddedFormat); + ret = csi2Subdev_->setFormat(csiMetaSinkPad, &embeddedFormat); + if (ret) + return ret; + ret = csi2Subdev_->setFormat(csiMetaSourcePad, &embeddedFormat); if (ret) return ret; }