@@ -6,6 +6,8 @@ 
  */
 #pragma once
 
+#include <libcamera/transform.h>
+
 // Description of a "camera mode", holding enough information for control
 // algorithms to adapt their behaviour to the different modes of the camera,
 // including binning, scaling, cropping etc.
@@ -33,6 +35,8 @@  struct CameraMode {
 	double noise_factor;
 	// line time in nanoseconds
 	double line_length;
+	// any camera transform *not* reflected already in the camera tuning
+	libcamera::Transform transform;
 };
 
 #ifdef __cplusplus
@@ -232,6 +232,33 @@  void IPARPi::configure(const CameraSensorInfo &sensorInfo,
 	/* Re-assemble camera mode using the sensor info. */
 	setMode(sensorInfo);
 
+	/*
+	 * The ipaConfig.data always gives us the user transform first. Note that
+	 * this will always make the LS table pointer (if present) element 1.
+	 */
+	mode_.transform = static_cast<libcamera::Transform>(ipaConfig.data[0]);
+
+	/* Store the lens shading table pointer and handle if available. */
+	if (ipaConfig.operation & RPI_IPA_CONFIG_LS_TABLE) {
+		/* Remove any previous table, if there was one. */
+		if (lsTable_) {
+			munmap(lsTable_, MAX_LS_GRID_SIZE);
+			lsTable_ = nullptr;
+		}
+
+		/* Map the LS table buffer into user space (now element 1). */
+		lsTableHandle_ = FileDescriptor(ipaConfig.data[1]);
+		if (lsTableHandle_.isValid()) {
+			lsTable_ = mmap(nullptr, MAX_LS_GRID_SIZE, PROT_READ | PROT_WRITE,
+					MAP_SHARED, lsTableHandle_.fd(), 0);
+
+			if (lsTable_ == MAP_FAILED) {
+				LOG(IPARPI, Error) << "dmaHeap mmap failure for LS table.";
+				lsTable_ = nullptr;
+			}
+		}
+	}
+
 	/* Pass the camera mode to the CamHelper to setup algorithms. */
 	helper_->SetCameraMode(mode_);
 
@@ -280,27 +307,6 @@  void IPARPi::configure(const CameraSensorInfo &sensorInfo,
 	}
 
 	lastMode_ = mode_;
-
-	/* Store the lens shading table pointer and handle if available. */
-	if (ipaConfig.operation & RPI_IPA_CONFIG_LS_TABLE) {
-		/* Remove any previous table, if there was one. */
-		if (lsTable_) {
-			munmap(lsTable_, MAX_LS_GRID_SIZE);
-			lsTable_ = nullptr;
-		}
-
-		/* Map the LS table buffer into user space. */
-		lsTableHandle_ = FileDescriptor(ipaConfig.data[0]);
-		if (lsTableHandle_.isValid()) {
-			lsTable_ = mmap(nullptr, MAX_LS_GRID_SIZE, PROT_READ | PROT_WRITE,
-					MAP_SHARED, lsTableHandle_.fd(), 0);
-
-			if (lsTable_ == MAP_FAILED) {
-				LOG(IPARPI, Error) << "dmaHeap mmap failure for LS table.";
-				lsTable_ = nullptr;
-			}
-		}
-	}
 }
 
 void IPARPi::mapBuffers(const std::vector<IPABuffer> &buffers)
@@ -1189,6 +1189,9 @@  int RPiCameraData::configureIPA(CameraConfiguration *config)
 	entityControls.emplace(0, unicam_[Unicam::Image].dev()->controls());
 	entityControls.emplace(1, isp_[Isp::Input].dev()->controls());
 
+	/* Always send the user transform to the IPA. */
+	ipaConfig.data = { static_cast<unsigned int>(config->transform) };
+
 	/* Allocate the lens shading table via dmaHeap and pass to the IPA. */
 	if (!lsTable_.isValid()) {
 		lsTable_ = dmaHeap_.alloc("ls_grid", MAX_LS_GRID_SIZE);
@@ -1197,7 +1200,7 @@  int RPiCameraData::configureIPA(CameraConfiguration *config)
 
 		/* Allow the IPA to mmap the LS table via the file descriptor. */
 		ipaConfig.operation = RPI_IPA_CONFIG_LS_TABLE;
-		ipaConfig.data = { static_cast<unsigned int>(lsTable_.fd()) };
+		ipaConfig.data.push_back(static_cast<unsigned int>(lsTable_.fd()));
 	}
 
 	CameraSensorInfo sensorInfo = {};