diff --git a/src/ipa/libipa/algorithms/af_hill_climbing.cpp b/src/ipa/libipa/algorithms/af_hill_climbing.cpp
index 244b8803..0fb17df3 100644
--- a/src/ipa/libipa/algorithms/af_hill_climbing.cpp
+++ b/src/ipa/libipa/algorithms/af_hill_climbing.cpp
@@ -63,9 +63,8 @@ LOG_DEFINE_CATEGORY(Af)
  * movement range rather than coarse search result.
  * \todo Implement setRange.
  * \todo Implement setSpeed.
- * \todo Implement setMeteringMode.
- * \todo Implement setWindows.
  * \todo Implement the AfPauseDeferred mode.
+ * \todo Implement support for multiple AF windows.
  */
 
 /**
@@ -99,6 +98,27 @@ int AfHillClimbing::init(int32_t minFocusPosition, int32_t maxFocusPosition,
 	return 0;
 }
 
+/**
+ * \brief Configure the AfHillClimbing with sensor information
+ * \param[in] outputSize Camera sensor output size
+ *
+ * This method should be called in the libcamera::ipa::Algorithm::configure()
+ * method of the platform layer.
+ */
+void AfHillClimbing::configure(const Size &outputSize)
+{
+	/*
+	 * Default AF window of 3/4 size of the camera sensor output,
+	 * placed at the center
+	 */
+	defaultWindow_ = Rectangle(static_cast<int>(outputSize.width / 8),
+				   static_cast<int>(outputSize.height / 8),
+				   3 * outputSize.width / 4,
+				   3 * outputSize.height / 4);
+
+	windowUpdateRequested.emit(defaultWindow_);
+}
+
 /**
  * \brief Run the auto focus algorithm loop
  * \param[in] currentContrast New value of contrast measured for current frame
@@ -185,6 +205,14 @@ void AfHillClimbing::skipFrames(uint32_t n)
 		framesToSkip_ = n;
 }
 
+/**
+ * \var AfHillClimbing::windowUpdateRequested
+ * \brief Signal emitted when change in AF window was requested
+ *
+ * Platform layer supporting AF windows should connect to this signal
+ * and configure the ISP with new window on each emition.
+ */
+
 void AfHillClimbing::setMode(controls::AfModeEnum mode)
 {
 	if (mode == mode_)
@@ -210,14 +238,36 @@ void AfHillClimbing::setSpeed([[maybe_unused]] controls::AfSpeedEnum speed)
 	LOG(Af, Error) << "setSpeed() not implemented!";
 }
 
-void AfHillClimbing::setMeteringMode([[maybe_unused]] controls::AfMeteringEnum metering)
+void AfHillClimbing::setMeteringMode(controls::AfMeteringEnum metering)
 {
-	LOG(Af, Error) << "setMeteringMode() not implemented!";
+	if (metering == meteringMode_)
+		return;
+
+	meteringMode_ = metering;
+
+	switch (metering) {
+	case controls::AfMeteringAuto:
+		windowUpdateRequested.emit(defaultWindow_);
+		break;
+	case controls::AfMeteringWindows:
+		windowUpdateRequested.emit(userWindow_);
+		break;
+	}
 }
 
-void AfHillClimbing::setWindows([[maybe_unused]] Span<const Rectangle> windows)
+void AfHillClimbing::setWindows(Span<const Rectangle> windows)
 {
-	LOG(Af, Error) << "setWindows() not implemented!";
+	if (windows.size() != 1) {
+		LOG(Af, Error) << "Only one AF window is supported";
+		return;
+	}
+
+	LOG(Af, Debug) << "setWindows: " << windows[0];
+
+	userWindow_ = windows[0];
+
+	if (meteringMode_ == controls::AfMeteringWindows)
+		windowUpdateRequested.emit(userWindow_);
 }
 
 void AfHillClimbing::setTrigger(controls::AfTriggerEnum trigger)
diff --git a/src/ipa/libipa/algorithms/af_hill_climbing.h b/src/ipa/libipa/algorithms/af_hill_climbing.h
index 2147939b..0f7c65db 100644
--- a/src/ipa/libipa/algorithms/af_hill_climbing.h
+++ b/src/ipa/libipa/algorithms/af_hill_climbing.h
@@ -10,6 +10,7 @@
 #pragma once
 
 #include <libcamera/base/log.h>
+#include <libcamera/base/signal.h>
 
 #include "af.h"
 
@@ -26,12 +27,15 @@ class AfHillClimbing : public Af
 public:
 	int init(int32_t minFocusPosition, int32_t maxFocusPosition,
 		 const YamlObject &tuningData);
+	void configure(const Size &outputSize);
 	int32_t process(double currentContrast);
 	void skipFrames(uint32_t n);
 
 	controls::AfStateEnum state() override { return state_; }
 	controls::AfPauseStateEnum pauseState() override { return pauseState_; }
 
+	Signal<const Rectangle &> windowUpdateRequested;
+
 private:
 	void setMode(controls::AfModeEnum mode) override;
 	void setRange(controls::AfRangeEnum range) override;
@@ -54,6 +58,7 @@ private:
 	controls::AfModeEnum mode_ = controls::AfModeManual;
 	controls::AfStateEnum state_ = controls::AfStateIdle;
 	controls::AfPauseStateEnum pauseState_ = controls::AfPauseStateRunning;
+	controls::AfMeteringEnum meteringMode_ = controls::AfMeteringAuto;
 
 	/* Current focus lens position. */
 	int32_t lensPosition_ = 0;
@@ -84,6 +89,11 @@ private:
 
 	/* Max ratio of variance change, 0.0 < maxChange_ < 1.0. */
 	double maxChange_;
+
+	/* Default AF window. */
+	Rectangle defaultWindow_;
+	/* AF window set by user using AF_WINDOWS control. */
+	Rectangle userWindow_;
 };
 
 } /* namespace ipa::algorithms */
