diff --git a/src/ipa/rkisp1/algorithms/af.cpp b/src/ipa/rkisp1/algorithms/af.cpp
index abf5d91f..794fa59e 100644
--- a/src/ipa/rkisp1/algorithms/af.cpp
+++ b/src/ipa/rkisp1/algorithms/af.cpp
@@ -31,18 +31,48 @@ namespace libcamera::ipa::rkisp1::algorithms {
  *   amount of time on each movement. This parameter should be set according
  *   to the worst case  - the number of frames it takes to move lens between
  *   limit positions.
+ * - **isp-threshold:** Threshold used for minimizing the influence of noise.
+ *   This affects the ISP sharpness calculation.
+ * - **isp-var-shift:** The number of bits for the shift operation at the end
+ *   of the calculation chain. This affects the ISP sharpness calculation.
+ *
+ * \sa libcamera::ipa::common::algorithms::AfHillClimbing for additional tuning
+ * parameters.
  */
 
 LOG_DEFINE_CATEGORY(RkISP1Af)
 
+namespace {
+
+constexpr rkisp1_cif_isp_window rectangleToIspWindow(const Rectangle &rectangle)
+{
+	return rkisp1_cif_isp_window{
+		.h_offs = static_cast<uint16_t>(rectangle.x),
+		.v_offs = static_cast<uint16_t>(rectangle.y),
+		.h_size = static_cast<uint16_t>(rectangle.width),
+		.v_size = static_cast<uint16_t>(rectangle.height)
+	};
+}
+
+} /* namespace */
+
+Af::Af()
+{
+	af.windowUpdateRequested.connect(this, &Af::updateCurrentWindow);
+}
+
 /**
  * \copydoc libcamera::ipa::Algorithm::init
  */
 int Af::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData)
 {
 	waitFramesLens_ = tuningData["wait-frames-lens"].get<uint32_t>(1);
+	ispThreshold_ = tuningData["isp-threshold"].get<uint32_t>(128);
+	ispVarShift_ = tuningData["isp-var-shift"].get<uint32_t>(4);
 
-	LOG(RkISP1Af, Debug) << "waitFramesLens_: " << waitFramesLens_;
+	LOG(RkISP1Af, Debug) << "waitFramesLens_: " << waitFramesLens_
+			     << ", ispThreshold_: " << ispThreshold_
+			     << ", ispVarShift_: " << ispVarShift_;
 
 	return af.init(tuningData);
 }
@@ -77,6 +107,32 @@ void Af::queueRequest([[maybe_unused]] IPAContext &context,
 	af.queueRequest(controls);
 }
 
+/**
+ * \copydoc libcamera::ipa::Algorithm::prepare
+ */
+void Af::prepare([[maybe_unused]] IPAContext &context,
+		 [[maybe_unused]] const uint32_t frame,
+		 [[maybe_unused]] IPAFrameContext &frameContext,
+		 rkisp1_params_cfg *params)
+{
+	if (updateWindow_) {
+		params->meas.afc_config.num_afm_win = 1;
+		params->meas.afc_config.thres = ispThreshold_;
+		params->meas.afc_config.var_shift = ispVarShift_;
+		params->meas.afc_config.afm_win[0] =
+			rectangleToIspWindow(*updateWindow_);
+
+		params->module_cfg_update |= RKISP1_CIF_ISP_MODULE_AFC;
+		params->module_ens |= RKISP1_CIF_ISP_MODULE_AFC;
+		params->module_en_update |= RKISP1_CIF_ISP_MODULE_AFC;
+
+		updateWindow_.reset();
+
+		/* Wait one frame for the ISP to apply changes */
+		af.setFramesToSkip(1);
+	}
+}
+
 /**
  * \copydoc libcamera::ipa::Algorithm::process
  */
@@ -102,6 +158,11 @@ void Af::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
 	}
 }
 
+void Af::updateCurrentWindow(const Rectangle &window)
+{
+	updateWindow_ = window;
+}
+
 REGISTER_IPA_ALGORITHM(Af, "Af")
 
 } /* namespace libcamera::ipa::rkisp1::algorithms */
diff --git a/src/ipa/rkisp1/algorithms/af.h b/src/ipa/rkisp1/algorithms/af.h
index 85de0a64..df2ca31a 100644
--- a/src/ipa/rkisp1/algorithms/af.h
+++ b/src/ipa/rkisp1/algorithms/af.h
@@ -18,20 +18,31 @@ namespace libcamera::ipa::rkisp1::algorithms {
 class Af : public Algorithm
 {
 public:
+	Af();
+
 	int init(IPAContext &context, const YamlObject &tuningData) override;
 	int configure(IPAContext &context,
 		      const IPACameraSensorInfo &configInfo) override;
 	void queueRequest(IPAContext &context, const uint32_t frame,
 			  IPAFrameContext &frameContext,
 			  const ControlList &controls) override;
+	void prepare(IPAContext &context, const uint32_t frame,
+		     IPAFrameContext &frameContext,
+		     rkisp1_params_cfg *params) override;
 	void process(IPAContext &context, const uint32_t frame,
 		     IPAFrameContext &frameContext,
 		     const rkisp1_stat_buffer *stats,
 		     ControlList &metadata) override;
 
 private:
+	void updateCurrentWindow(const Rectangle &window);
+
 	ipa::common::algorithms::AfHillClimbing af;
 
+	std::optional<Rectangle> updateWindow_;
+	uint32_t ispThreshold_;
+	uint32_t ispVarShift_;
+
 	/* Wait number of frames after changing lens position */
 	uint32_t waitFramesLens_;
 };
