diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp
index bd6ddde..83dd541 100644
--- a/src/libcamera/pipeline/vimc/vimc.cpp
+++ b/src/libcamera/pipeline/vimc/vimc.cpp
@@ -117,6 +117,17 @@ static const std::map<PixelFormat, uint32_t> pixelformats{
 	{ formats::BGR888, MEDIA_BUS_FMT_RGB888_1X24 },
 };
 
+static const std::map<PixelFormat, uint32_t> pixelFormatsRaw{
+	{ formats::SBGGR8, MEDIA_BUS_FMT_SBGGR8_1X8 },
+	{ formats::SGBRG8, MEDIA_BUS_FMT_SGBRG8_1X8 },
+	{ formats::SGRBG8, MEDIA_BUS_FMT_SGRBG8_1X8 },
+	{ formats::SRGGB8, MEDIA_BUS_FMT_SRGGB8_1X8 },
+	{ formats::SBGGR10, MEDIA_BUS_FMT_SBGGR10_1X10 },
+	{ formats::SGBRG10, MEDIA_BUS_FMT_SGBRG10_1X10 },
+	{ formats::SGRBG10, MEDIA_BUS_FMT_SGRBG10_1X10 },
+	{ formats::SRGGB10, MEDIA_BUS_FMT_SRGGB10_1X10 }
+};
+
 } /* namespace */
 
 VimcCameraConfiguration::VimcCameraConfiguration(VimcCameraData *data)
@@ -127,53 +138,90 @@ VimcCameraConfiguration::VimcCameraConfiguration(VimcCameraData *data)
 CameraConfiguration::Status VimcCameraConfiguration::validate()
 {
 	Status status = Valid;
+	bool hasRaw = false;
+	unsigned rindex = 2;
+	int ret;
 
 	if (config_.empty())
 		return Invalid;
 
 	/* Cap the number of entries to the available streams. */
-	if (config_.size() > 1) {
-		config_.resize(1);
+	if (config_.size() > 2) {
+		config_.resize(2);
 		status = Adjusted;
 	}
 
-	StreamConfiguration &cfg = config_[0];
-
-	/* Adjust the pixel format. */
-	const std::vector<libcamera::PixelFormat> formats = cfg.formats().pixelformats();
-	if (std::find(formats.begin(), formats.end(), cfg.pixelFormat) == formats.end()) {
-		LOG(VIMC, Debug) << "Adjusting format to BGR888";
-		cfg.pixelFormat = formats::BGR888;
-		status = Adjusted;
+	if (config_.size() > 1) {
+		if (config_[0].size.width < config_[1].size.width) {
+			rindex = 0;
+		} else {
+			rindex = 1;
+		}
+		hasRaw = true;
 	}
 
-	/* Clamp the size based on the device limits. */
-	const Size size = cfg.size;
-
-	/* The scaler hardcodes a x3 scale-up ratio. */
-	cfg.size.width = std::max(48U, std::min(4096U, cfg.size.width));
-	cfg.size.height = std::max(48U, std::min(2160U, cfg.size.height));
-	cfg.size.width -= cfg.size.width % 3;
-	cfg.size.height -= cfg.size.height % 3;
-
-	if (cfg.size != size) {
-		LOG(VIMC, Debug)
-			<< "Adjusting size to " << cfg.size.toString();
-		status = Adjusted;
+	for (unsigned i = 0; i < config_.size(); i++) {
+		const PixelFormatInfo &info = PixelFormatInfo::info(config_[i].pixelFormat);
+		if (info.isRaw(config_[i].pixelFormat)) {
+			rindex = i;
+			hasRaw = true;
+		}
 	}
 
-	cfg.bufferCount = 4;
+	for (unsigned i = 0; i < config_.size(); i++) {
+		StreamConfiguration &cfg = config_[i];
+		V4L2DeviceFormat format = {};
+		const Size size = cfg.size;
+		if (i == rindex) {
+			/* Clamp the size based on the device limits. */
+			cfg.size.width = std::max(16U, std::min(1365U, cfg.size.width));
+			cfg.size.height = std::max(16U, std::min(720U, cfg.size.height));
+			/* Adjust the pixel format. */
+			if (pixelFormatsRaw.find(cfg.pixelFormat) == pixelFormatsRaw.end()) {
+				LOG(VIMC, Debug) << "Adjusting format to SGRBG8";
+				cfg.pixelFormat = formats::SGRBG8;
+				status = Adjusted;
+			}
+			format.fourcc = data_->raw_->toV4L2PixelFormat(cfg.pixelFormat);
+			format.size = cfg.size;
+			ret = data_->raw_->tryFormat(&format);
+		} else {
+			const std::vector<libcamera::PixelFormat> formats = cfg.formats().pixelformats();
+			if (hasRaw) {
+				cfg.size.width = config_[(i + 1) % 2].size.width * 3;
+				cfg.size.height = config_[(i + 1) % 2].size.height * 3;
+			} else {
+				/* Clamp the size based on the device limits. */
+				cfg.size.width = std::max(48U, std::min(4096U, cfg.size.width));
+				cfg.size.height = std::max(48U, std::min(2160U, cfg.size.height));
+				/* The scaler hardcodes a x3 scale-up ratio. */
+				cfg.size.width -= cfg.size.width % 3;
+				cfg.size.height -= cfg.size.height % 3;
+			}
 
-	V4L2DeviceFormat format = {};
-	format.fourcc = data_->video_->toV4L2PixelFormat(cfg.pixelFormat);
-	format.size = cfg.size;
+			/* Adjust the pixel format. */
+			if (std::find(formats.begin(), formats.end(), cfg.pixelFormat) == formats.end()) {
+				LOG(VIMC, Debug) << "Adjusting format to BGR888";
+				cfg.pixelFormat = formats::BGR888;
+				status = Adjusted;
+			}
+			format.fourcc = data_->video_->toV4L2PixelFormat(cfg.pixelFormat);
+			format.size = cfg.size;
+			ret = data_->video_->tryFormat(&format);
+		}
 
-	int ret = data_->video_->tryFormat(&format);
-	if (ret)
-		return Invalid;
+		if (ret)
+			return Invalid;
+		if (cfg.size != size) {
+			LOG(VIMC, Debug)
+				<< "Adjusting size to " << cfg.size.toString();
+			status = Adjusted;
+		}
 
-	cfg.stride = format.planes[0].bpl;
-	cfg.frameSize = format.planes[0].size;
+		cfg.bufferCount = 4;
+		cfg.stride = format.planes[0].bpl;
+		cfg.frameSize = format.planes[0].size;
+	}
 
 	return status;
 }
@@ -194,35 +242,51 @@ CameraConfiguration *PipelineHandlerVimc::generateConfiguration(Camera *camera,
 
 	std::map<PixelFormat, std::vector<SizeRange>> formats;
 
-	for (const auto &pixelformat : pixelformats) {
-		/*
-		 * Kernels prior to v5.7 incorrectly report support for RGB888,
-		 * but it isn't functional within the pipeline.
-		 */
-		if (data->media_->version() < KERNEL_VERSION(5, 7, 0)) {
-			if (pixelformat.first != formats::BGR888) {
-				LOG(VIMC, Info)
-					<< "Skipping unsupported pixel format "
-					<< pixelformat.first.toString();
-				continue;
+	for (const StreamRole role : roles) {
+		switch (role) {
+		case StreamRole::StillCaptureRaw: {
+			for (const auto &pixelformat : pixelFormatsRaw) {
+				std::vector<SizeRange> sizes{
+					SizeRange{ { 16, 16 }, { 1365, 720 } }
+				};
+				formats[pixelformat.first] = sizes;
+			}
+			StreamConfiguration cfg(formats);
+			cfg.pixelFormat = formats::SGRBG8;
+			cfg.size = { 640, 360 };
+			cfg.bufferCount = 4;
+			config->addConfiguration(cfg);
+			break;
+		}
+		default:
+			for (const auto &pixelformat : pixelformats) {
+				/*
+				 * Kernels prior to v5.7 incorrectly report support for RGB888,
+				 * but it isn't functional within the pipeline.
+				 */
+				if (data->media_->version() < KERNEL_VERSION(5, 7, 0)) {
+					if (pixelformat.first != formats::BGR888) {
+						LOG(VIMC, Info)
+							<< "Skipping unsupported pixel format "
+							<< pixelformat.first.toString();
+						continue;
+					}
+				}
+
+				/* The scaler hardcodes a x3 scale-up ratio. */
+				std::vector<SizeRange> sizes{
+					SizeRange{ { 48, 48 }, { 4096, 2160 } }
+				};
+				formats[pixelformat.first] = sizes;
 			}
+			StreamConfiguration cfg(formats);
+			cfg.pixelFormat = formats::BGR888;
+			cfg.size = { 1920, 1080 };
+			cfg.bufferCount = 4;
+			config->addConfiguration(cfg);
+			break;
 		}
-
-		/* The scaler hardcodes a x3 scale-up ratio. */
-		std::vector<SizeRange> sizes{
-			SizeRange{ { 48, 48 }, { 4096, 2160 } }
-		};
-		formats[pixelformat.first] = sizes;
 	}
-
-	StreamConfiguration cfg(formats);
-
-	cfg.pixelFormat = formats::BGR888;
-	cfg.size = { 1920, 1080 };
-	cfg.bufferCount = 4;
-
-	config->addConfiguration(cfg);
-
 	config->validate();
 
 	return config;
