diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp
index bc8e65cb0811..988c1f5b2ad2 100644
--- a/src/ipa/rpi/common/ipa_base.cpp
+++ b/src/ipa/rpi/common/ipa_base.cpp
@@ -18,15 +18,18 @@
 #include "controller/af_algorithm.h"
 #include "controller/af_status.h"
 #include "controller/agc_algorithm.h"
+#include "controller/alsc_status.h"
 #include "controller/awb_algorithm.h"
 #include "controller/awb_status.h"
 #include "controller/black_level_status.h"
 #include "controller/ccm_algorithm.h"
 #include "controller/ccm_status.h"
 #include "controller/contrast_algorithm.h"
+#include "controller/contrast_status.h"
 #include "controller/denoise_algorithm.h"
 #include "controller/hdr_algorithm.h"
 #include "controller/lux_status.h"
+#include "controller/noise_status.h"
 #include "controller/sharpen_algorithm.h"
 #include "controller/statistics.h"
 
@@ -80,6 +83,7 @@ const ControlInfoMap::Map ipaControls{
 		      static_cast<int64_t>(defaultMaxFrameDuration.get<std::micro>()),
 		      std::span<const int64_t, 2>{ { static_cast<int64_t>(defaultMinFrameDuration.get<std::micro>()),
 						     static_cast<int64_t>(defaultMinFrameDuration.get<std::micro>()) } }) },
+	{ &controls::EnableLensShadingCorrectionMapOutput, ControlInfo(false, true, false) },
 	{ &controls::draft::NoiseReductionMode, ControlInfo(controls::draft::NoiseReductionModeValues) },
 	{ &controls::rpi::StatsOutputEnable, ControlInfo(false, true, false) },
 };
@@ -121,7 +125,7 @@ LOG_DEFINE_CATEGORY(IPARPI)
 namespace ipa::RPi {
 
 IpaBase::IpaBase()
-	: controller_(), frameLengths_(FrameLengthsQueueSize, 0s), statsMetadataOutput_(false),
+	: controller_(), frameLengths_(FrameLengthsQueueSize, 0s), lscMapsOutput_(false), statsMetadataOutput_(false),
 	  stitchSwapBuffers_(false), frameCount_(0), mistrustCount_(0), lastRunTimestamp_(0),
 	  firstStart_(true), flickerState_({ 0, 0s }), awbEnabled_(true)
 {
@@ -237,7 +241,6 @@ int32_t IpaBase::configure(const IPACameraSensorInfo &sensorInfo, const ConfigPa
 		agcStatus.exposureTime = defaultExposureTime;
 		agcStatus.analogueGain = defaultAnalogueGain;
 		applyAGC(&agcStatus, ctrls);
-
 	}
 
 	result->sensorControls = std::move(ctrls);
@@ -772,8 +775,8 @@ static const std::map<int32_t, std::string> HdrModeTable = {
 
 void IpaBase::applyControls(const ControlList &controls)
 {
-	using RPiController::AgcAlgorithm;
 	using RPiController::AfAlgorithm;
+	using RPiController::AgcAlgorithm;
 	using RPiController::ContrastAlgorithm;
 	using RPiController::DenoiseAlgorithm;
 	using RPiController::HdrAlgorithm;
@@ -1454,6 +1457,10 @@ void IpaBase::applyControls(const ControlList &controls)
 			break;
 		}
 
+		case controls::ENABLE_LENS_SHADING_CORRECTION_MAP_OUTPUT:
+			lscMapsOutput_ = ctrl.second.get<bool>();
+			break;
+
 		case controls::rpi::STATS_OUTPUT_ENABLE:
 			statsMetadataOutput_ = ctrl.second.get<bool>();
 			break;
@@ -1647,6 +1654,43 @@ void IpaBase::reportMetadata(unsigned int ipaContext)
 			libcameraMetadata_.set(controls::HdrChannel, controls::HdrChannelNone);
 	}
 
+	NoiseStatus *noiseStatus = rpiMetadata.getLocked<NoiseStatus>("noise.status");
+	if (noiseStatus) {
+		float noiseProfile[] = { static_cast<float>(noiseStatus->noiseSlope),
+					 static_cast<float>(noiseStatus->noiseConstant) };
+
+		libcameraMetadata_.set(controls::NoiseProfile, noiseProfile);
+	}
+
+	ContrastStatus *contrastStatus = rpiMetadata.getLocked<ContrastStatus>("contrast.status");
+	if (contrastStatus && contrastStatus->gammaCurve.size() > 0) {
+		std::vector<float> contrast;
+		contrast.reserve(contrastStatus->gammaCurve.size() * 2);
+
+		contrastStatus->gammaCurve.map([&](double x, double y) {
+			contrast.emplace_back(static_cast<float>(x));
+			contrast.emplace_back(static_cast<float>(y));
+		});
+		libcameraMetadata_.set(controls::ToneCurve, contrast);
+	}
+
+	if (lscMapsOutput_) {
+		AlscStatus *alscStatus = rpiMetadata.getLocked<AlscStatus>("alsc.status");
+		if (alscStatus) {
+			uint32_t elements = alscStatus->cols * alscStatus->rows;
+			std::vector<float> map(3 * elements);
+
+			std::copy(alscStatus->r.begin(), alscStatus->r.end(), map.begin() + 0 * elements);
+			std::copy(alscStatus->g.begin(), alscStatus->g.end(), map.begin() + 1 * elements);
+			std::copy(alscStatus->b.begin(), alscStatus->b.end(), map.begin() + 2 * elements);
+
+			uint32_t sizeTable[] = { 3, alscStatus->cols, alscStatus->rows };
+			libcameraMetadata_.set(controls::LensShadingCorrectionMaps, map);
+			libcameraMetadata_.set(controls::LensShadingCorrectionMapSize, sizeTable);
+			libcameraMetadata_.set(controls::EnableLensShadingCorrectionMapOutput, true);
+		}
+	}
+
 	metadataReady.emit(libcameraMetadata_);
 }
 
diff --git a/src/ipa/rpi/common/ipa_base.h b/src/ipa/rpi/common/ipa_base.h
index 0d7842f1f742..dbd6a8e5056f 100644
--- a/src/ipa/rpi/common/ipa_base.h
+++ b/src/ipa/rpi/common/ipa_base.h
@@ -68,6 +68,7 @@ protected:
 	std::deque<utils::Duration> frameLengths_;
 	utils::Duration lastTimeout_;
 	ControlList libcameraMetadata_;
+	bool lscMapsOutput_;
 	bool statsMetadataOutput_;
 
 	/* Remember the HDR status after a mode switch. */
diff --git a/src/ipa/rpi/common/meson.build b/src/ipa/rpi/common/meson.build
index 73d2ee732339..cb3555a802c0 100644
--- a/src/ipa/rpi/common/meson.build
+++ b/src/ipa/rpi/common/meson.build
@@ -5,7 +5,7 @@ rpi_ipa_common_sources = files([
 ])
 
 rpi_ipa_common_includes = [
-    include_directories('..'),
+    include_directories('..','../..'),
 ]
 
 rpi_ipa_common_deps = [
diff --git a/src/ipa/rpi/controller/rpi/alsc.cpp b/src/ipa/rpi/controller/rpi/alsc.cpp
index e13d6c6c2832..c0d39d1fe41b 100644
--- a/src/ipa/rpi/controller/rpi/alsc.cpp
+++ b/src/ipa/rpi/controller/rpi/alsc.cpp
@@ -409,6 +409,9 @@ void Alsc::prepare(Metadata *imageMetadata)
 	status.r = prevSyncResults_[0].data();
 	status.g = prevSyncResults_[1].data();
 	status.b = prevSyncResults_[2].data();
+	status.cols = config_.tableSize.width;
+	status.rows = config_.tableSize.height;
+
 	imageMetadata->set("alsc.status", status);
 	/*
 	 * Put the results in the global metadata as well. This will be used by
diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml
index 89991d03d79a..608681f3e395 100644
--- a/src/libcamera/control_ids_core.yaml
+++ b/src/libcamera/control_ids_core.yaml
@@ -1376,4 +1376,42 @@ controls:
         The nominal range is [-180, 180], where 0° leaves hues unchanged and the
         range wraps around continuously, with 180° == -180°.
 
+  - EnableLensShadingCorrectionMapOutput:
+      type: bool
+      direction: inout
+      description: |
+        Indicates if the lens shading correction maps should be set in frame-
+        metadata for each frame. Returns true if tables are successfully set.
+
+  - LensShadingCorrectionMaps:
+      type: float
+      direction: out
+      description: |
+        A map giving the lens shading correction factors. Dimesnions of the
+        returned table is [number of channels, sizeX, sizeY] (planar tables)
+      size: [n]
+
+  - LensShadingCorrectionMapSize:
+      type: uint32_t
+      direction: out
+      description: |
+        The number of channels/maps and the size of the lens shading correction
+        maps in pixels. E.g. [3, 32, 32]
+      size: [3]
+
+  - ToneCurve:
+      type: float
+      direction: out
+      description: |
+        A profile tone curve to apply on linear RGB - as it seems it has the sRGB
+        gamma curve baked in.
+      size: [n]
+
+  - NoiseProfile:
+      type: float
+      direction: out
+      description: |
+        The noise profile [Scale, Offset].
+      size: [2]
+
 ...
