[WIP,RFC,25/26] pipeline: mali-c55: Use generic RAW formats
diff mbox series

Message ID 20261023-b4-raw-model-v1-25-eadb9948901b@ideasonboard.com
State New
Headers show
Series
  • Support the new common raw sensor model
Related show

Commit Message

Jai Luthra Oct. 23, 2026, 10:58 a.m. UTC
Split the CFA from the pixel format. Ensure we populate the CFA order
for the source (sensor, memory, TPG) in generateConfiguration() and
update it during validate() depending upon the transformations.

With generic formats the logic for selecting output pixel formats for
raw streams is quite simplified, as we only work with 16-bit, which is
formats::RAW16. So we no longer need adjustRawFormat() helper, and can
replace it with a simple check to ensure the sensor advertises raw formats.

We still need to figure out the source mbus code that has the largest
possible bit-depth, so we repurpose pixfmtToMbusCode() to look for one,
given a CFA order. Note that the Mali-C55 kernel drivers are not yet
updated to work with the new generic media bus codes, so we skip those.

Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>
---
 src/libcamera/pipeline/mali-c55/mali-c55.cpp | 162 ++++++++++++---------------
 1 file changed, 70 insertions(+), 92 deletions(-)

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
index af518d0b2c28..421f3d925a3f 100644
--- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
+++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
@@ -76,10 +76,7 @@  const std::map<libcamera::PixelFormat, unsigned int> maliC55FmtToCode = {
 	{ formats::NV21, MEDIA_BUS_FMT_YUV10_1X30 },
 
 	/* RAW formats, FR pipe only. */
-	{ formats::SGBRG16, MEDIA_BUS_FMT_SGBRG16_1X16 },
-	{ formats::SRGGB16, MEDIA_BUS_FMT_SRGGB16_1X16 },
-	{ formats::SBGGR16, MEDIA_BUS_FMT_SBGGR16_1X16 },
-	{ formats::SGRBG16, MEDIA_BUS_FMT_SGRBG16_1X16 },
+	{ formats::RAW16, MEDIA_BUS_FMT_RAW_16 },
 };
 
 constexpr Size kMaliC55MinInputSize = { 640, 480 };
@@ -191,13 +188,33 @@  public:
 		}, input_);
 	}
 
-	int pixfmtToMbusCode(const PixelFormat &pixFmt) const;
-	const PixelFormat &bestRawFormat() const;
+	ColorFilterArray bayerOrder(Transform t) const
+	{
+		return std::visit(utils::overloaded{
+			[&](const Tpg &tpg) -> ColorFilterArray {
+				V4L2Subdevice::Formats formats = tpg.sd_->formats(0);
+				for (const auto &[code, sizes] : formats) {
+					auto cfa = ColorFilterArray::fromMbusCode(code);
+					if (cfa)
+						return cfa.value();
+				}
+				return ColorFilterArray::MONO;
+			},
+			[&](const Inline &in) -> ColorFilterArray {
+				return in.sensor_->bayerOrder(t);
+			},
+			[&](const Memory &mem) -> ColorFilterArray {
+				return mem.cru_->sensor()->bayerOrder(t);
+			},
+		}, input_);
+	}
+
+	int bestMbusCode(ColorFilterArray cfa) const;
+	bool isSensorRaw() const;
 
 	void updateControls(const ControlInfoMap &ipaControls);
 
-	PixelFormat adjustRawFormat(const PixelFormat &pixFmt) const;
-	Size adjustRawSizes(const PixelFormat &pixFmt, const Size &rawSize) const;
+	Size adjustRawSizes(const Size &rawSize, unsigned int rawCode) const;
 
 	Stream frStream_;
 	Stream dsStream_;
@@ -305,21 +322,13 @@  void MaliC55CameraData::setSensorControls(const ControlList &sensorControls)
 }
 
 /*
- * The Mali C55 ISP can only produce 16-bit RAW output in bypass modes, but the
- * sensors connected to it might produce 8/10/12/16 bits. We simply search the
- * sensor's supported formats for the one with a matching bayer order and the
- * greatest bitdepth.
+ * The Mali C55 ISP can only accept as input RAW20 and can only produce as
+ * output RAW16. The sensors connected to it might produce 8/10/12/16 bits.
+ * We simply search the sensor's supported formats for the one with greatest
+ * bitdepth and matches the bayer color filter array order.
  */
-int MaliC55CameraData::pixfmtToMbusCode(const PixelFormat &pixFmt) const
+int MaliC55CameraData::bestMbusCode(ColorFilterArray cfa) const
 {
-	auto it = maliC55FmtToCode.find(pixFmt);
-	if (it == maliC55FmtToCode.end())
-		return -EINVAL;
-
-	BayerFormat bayerFormat = BayerFormat::fromMbusCode(it->second);
-	if (!bayerFormat.isValid())
-		return -EINVAL;
-
 	V4L2Subdevice::Formats formats = subdev()->formats(0);
 	unsigned int sensorMbusCode = 0;
 	unsigned int bitDepth = 0;
@@ -329,7 +338,12 @@  int MaliC55CameraData::pixfmtToMbusCode(const PixelFormat &pixFmt) const
 		if (!sdBayerFormat.isValid())
 			continue;
 
-		if (sdBayerFormat.cfa.order != bayerFormat.cfa.order)
+		/* The pipeline currently does not support generic codes */
+		if (MediaBusFormatInfo::info(code).genericRaw)
+			continue;
+
+		auto c = ColorFilterArray::fromMbusCode(code);
+		if (!c || c != cfa)
 			continue;
 
 		if (sdBayerFormat.bitDepth > bitDepth) {
@@ -344,38 +358,20 @@  int MaliC55CameraData::pixfmtToMbusCode(const PixelFormat &pixFmt) const
 	return sensorMbusCode;
 }
 
-/*
- * Find a RAW PixelFormat supported by both the ISP and the sensor.
- *
- * The situation is mildly complicated by the fact that we expect the sensor to
- * output something like RAW8/10/12/16, but the ISP can only accept as input
- * RAW20 and can only produce as output RAW16. The one constant in that is the
- * bayer order of the data, so we'll simply check that the sensor produces a
- * format with a bayer order that matches that of one of the formats we support,
- * and select that.
- */
-const PixelFormat &MaliC55CameraData::bestRawFormat() const
+bool MaliC55CameraData::isSensorRaw() const
 {
-	static const PixelFormat invalidPixFmt = {};
+	if (!std::holds_alternative<Tpg>(input_))
+		return this->sensor()->isRaw();
 
 	for (const auto &fmt : subdev()->formats(0)) {
 		BayerFormat sensorBayer = BayerFormat::fromMbusCode(fmt.first);
 
-		if (!sensorBayer.isValid())
-			continue;
-
-		for (const auto &[pixFmt, rawCode] : maliC55FmtToCode) {
-			if (!isFormatRaw(pixFmt))
-				continue;
-
-			BayerFormat bayer = BayerFormat::fromMbusCode(rawCode);
-			if (bayer.cfa.order == sensorBayer.cfa.order)
-				return pixFmt;
-		}
+		if (sensorBayer.isValid())
+			return true;
 	}
 
-	LOG(MaliC55, Error) << "Sensor doesn't provide a compatible format";
-	return invalidPixFmt;
+	LOG(MaliC55, Error) << "Sensor doesn't provide a raw bayer format";
+	return false;
 }
 
 void MaliC55CameraData::updateControls(const ControlInfoMap &ipaControls)
@@ -402,34 +398,13 @@  void MaliC55CameraData::updateControls(const ControlInfoMap &ipaControls)
 	controlInfo_ = ControlInfoMap(std::move(controls), controls::controls);
 }
 
-/*
- * Make sure the provided raw pixel format is supported and adjust it to
- * one of the supported ones if it's not.
- */
-PixelFormat MaliC55CameraData::adjustRawFormat(const PixelFormat &rawFmt) const
-{
-	/* Make sure the RAW mbus code is supported by the image source. */
-	int rawCode = pixfmtToMbusCode(rawFmt);
-	if (rawCode < 0)
-		return bestRawFormat();
-
-	const auto rawSizes = sizes(rawCode);
-	if (rawSizes.empty())
-		return bestRawFormat();
-
-	return rawFmt;
-}
-
-Size MaliC55CameraData::adjustRawSizes(const PixelFormat &rawFmt, const Size &size) const
+Size MaliC55CameraData::adjustRawSizes(const Size &size,
+				       unsigned int rawCode) const
 {
 	/* Expand the RAW size to the minimum ISP input size. */
 	Size rawSize = size.expandedTo(kMaliC55MinInputSize);
 
 	/* Check if the size is natively supported. */
-	int rawCode = pixfmtToMbusCode(rawFmt);
-	if (rawCode < 0)
-		return {};
-
 	const auto rawSizes = sizes(rawCode);
 	auto sizeIt = std::find(rawSizes.begin(), rawSizes.end(), rawSize);
 	if (sizeIt != rawSizes.end())
@@ -552,21 +527,28 @@  CameraConfiguration::Status MaliC55CameraConfiguration::validate()
 		rawConfig = &config;
 	}
 
+	/* Populate a valid sensor mbus code */
+	ColorFilterArray cfa = data_->bayerOrder(combinedTransform_);
+	int code = data_->bestMbusCode(cfa);
+	if (code < 0)
+		return Invalid;
+
+	sensorFormat_.code = code;
+
 	/*
 	 * The C55 can not upscale. Limit the configuration to the ISP
 	 * capabilities and the sensor resolution.
 	 */
 	Size maxSize = kMaliC55MaxSize.boundedTo(data_->resolution());
 	if (rawConfig) {
-		/*
-		 * \todo Take into account the Bayer components ordering once
-		 * we support rotations.
-		 */
-		PixelFormat rawFormat =
-			data_->adjustRawFormat(rawConfig->pixelFormat);
+		if (!rawConfig->bayerOrder ||
+		    rawConfig->bayerOrder.value() != cfa) {
+			rawConfig->bayerOrder = cfa;
+			status = Adjusted;
+		}
 
-		if (!rawFormat.isValid())
-			return Invalid;
+		/* C55 can only produce 16-bit raw output */
+		PixelFormat rawFormat = formats::RAW16;
 
 		if (rawFormat != rawConfig->pixelFormat) {
 			LOG(MaliC55, Debug)
@@ -576,7 +558,7 @@  CameraConfiguration::Status MaliC55CameraConfiguration::validate()
 		}
 
 		Size rawSize =
-			data_->adjustRawSizes(rawFormat, rawConfig->size);
+			data_->adjustRawSizes(rawConfig->size, sensorFormat_.code);
 		if (rawSize != rawConfig->size) {
 			LOG(MaliC55, Debug)
 				<< "RAW sizes adjusted to " << rawSize;
@@ -637,19 +619,15 @@  CameraConfiguration::Status MaliC55CameraConfiguration::validate()
 
 	/* If there's a RAW config, sensor configuration follows it. */
 	if (rawConfig) {
-		sensorFormat_.code = data_->pixfmtToMbusCode(rawConfig->pixelFormat);
 		sensorFormat_.size = rawConfig->size.expandedTo(minSensorSize);
 
 		return status;
 	}
 
 	/* If there's no RAW config, compute the sensor configuration here. */
-	PixelFormat rawFormat = data_->bestRawFormat();
-	if (!rawFormat.isValid())
+	if (!data_->isSensorRaw())
 		return Invalid;
 
-	sensorFormat_.code = data_->pixfmtToMbusCode(rawFormat);
-
 	uint16_t distance = std::numeric_limits<uint16_t>::max();
 	const auto sizes = data_->sizes(sensorFormat_.code);
 	Size bestSize;
@@ -799,6 +777,7 @@  PipelineHandlerMaliC55::generateConfiguration(Camera *camera,
 	std::unique_ptr<CameraConfiguration> config =
 		std::make_unique<MaliC55CameraConfiguration>(data);
 	bool frPipeAvailable = true;
+	ColorFilterArray cameraCfa = data->bayerOrder(Transform::Identity);
 
 	if (roles.empty())
 		return config;
@@ -838,12 +817,8 @@  PipelineHandlerMaliC55::generateConfiguration(Camera *camera,
 			break;
 
 		case StreamRole::Raw:
-			pixelFormat = data->bestRawFormat();
-			if (!pixelFormat.isValid()) {
-				LOG(MaliC55, Error)
-					<< "Camera does not support RAW formats";
+			if (!data->isSensorRaw())
 				return nullptr;
-			}
 
 			size = data->resolution();
 			break;
@@ -865,7 +840,7 @@  PipelineHandlerMaliC55::generateConfiguration(Camera *camera,
 
 			if (isRaw) {
 				/* Make sure the mbus code is supported. */
-				int rawCode = data->pixfmtToMbusCode(pixFmt);
+				int rawCode = data->bestMbusCode(cameraCfa);
 				if (rawCode < 0)
 					continue;
 
@@ -896,6 +871,9 @@  PipelineHandlerMaliC55::generateConfiguration(Camera *camera,
 		cfg.bufferCount = 4;
 		cfg.size = size;
 
+		if (role == StreamRole::Raw)
+			cfg.bayerOrder = cameraCfa;
+
 		config->addConfiguration(cfg);
 	}
 
@@ -1180,10 +1158,10 @@  int PipelineHandlerMaliC55::configure(Camera *camera,
 	 * affected by any flips that we've configured)
 	 */
 	const Transform &combinedTransform = maliConfig->combinedTransform();
-	ColorFilterArray::Order cfaOrder = data->sensor()->bayerOrder(combinedTransform);
+	ColorFilterArray cfa = data->bayerOrder(combinedTransform);
 
 	ControlInfoMap ipaControls;
-	ret = data->ipa_->configure(ipaConfig, utils::to_underlying(cfaOrder),
+	ret = data->ipa_->configure(ipaConfig, utils::to_underlying(cfa.order),
 				    &ipaControls);
 	if (ret) {
 		LOG(MaliC55, Error) << "Failed to configure IPA";