diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
index 81ec359981..f90cae253f 100644
--- a/include/libcamera/internal/pipeline_handler.h
+++ b/include/libcamera/internal/pipeline_handler.h
@@ -59,7 +59,6 @@ public:
 	void stop(Camera *camera);
 	bool hasPendingRequests(const Camera *camera) const;
 
-	void registerRequest(Request *request);
 	void queueRequest(Request *request);
 
 	static bool completeBuffer(Request *request, FrameBuffer *buffer)
diff --git a/include/libcamera/internal/request.h b/include/libcamera/internal/request.h
index 382ed28bca..8f570e4f79 100644
--- a/include/libcamera/internal/request.h
+++ b/include/libcamera/internal/request.h
@@ -7,19 +7,13 @@
 
 #pragma once
 
-#include <chrono>
-#include <map>
-#include <memory>
 #include <stdint.h>
 #include <unordered_set>
 
 #include <libcamera/base/event_notifier.h>
-#include <libcamera/base/timer.h>
 
 #include <libcamera/request.h>
 
-using namespace std::chrono_literals;
-
 namespace libcamera {
 
 class Camera;
@@ -43,26 +37,17 @@ public:
 	void cancel();
 	void reset();
 
-	void prepare(std::chrono::milliseconds timeout = 0ms);
-	Signal<> prepared;
-
 private:
 	friend class PipelineHandler;
 	friend std::ostream &operator<<(std::ostream &out, const Request &r);
 
 	void doCancelRequest();
-	void emitPrepareCompleted();
-	void notifierActivated(FrameBuffer *buffer);
-	void timeout();
 
 	Camera *camera_;
 	bool cancelled_;
 	uint32_t sequence_ = 0;
-	bool prepared_ = false;
 
 	std::unordered_set<FrameBuffer *> pending_;
-	std::map<FrameBuffer *, EventNotifier> notifiers_;
-	std::unique_ptr<Timer> timer_;
 	ControlList metadata_;
 };
 
diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
index 31ab59e0b7..27dae3a403 100644
--- a/src/libcamera/camera.cpp
+++ b/src/libcamera/camera.cpp
@@ -1294,12 +1294,7 @@ std::unique_ptr<Request> Camera::createRequest(uint64_t cookie)
 	if (ret < 0)
 		return nullptr;
 
-	std::unique_ptr<Request> request = std::make_unique<Request>(this, cookie);
-
-	/* Associate the request with the pipeline handler. */
-	d->pipe_->registerRequest(request.get());
-
-	return request;
+	return std::make_unique<Request>(this, cookie);
 }
 
 /**
diff --git a/src/libcamera/fence.cpp b/src/libcamera/fence.cpp
index 73299b4027..92d1b37366 100644
--- a/src/libcamera/fence.cpp
+++ b/src/libcamera/fence.cpp
@@ -28,8 +28,6 @@ namespace libcamera {
  * the Fence to be signalled before allowing the camera device to actually
  * access the memory area described by the FrameBuffer.
  *
- * \sa Request::addBuffer()
- *
  * By using a fence, applications can then synchronize between frame buffer
  * consumers and producers, as for example a display device and a camera, to
  * guarantee that a new data transfers only happen once the existing frames have
@@ -68,9 +66,6 @@ namespace libcamera {
  *
  * A failure in waiting for a Fence to complete will result in the Request to
  * complete in failed state.
- *
- * \sa Request::prepare()
- * \sa PipelineHandler::doQueueRequests()
  */
 
 /**
diff --git a/src/libcamera/framebuffer.cpp b/src/libcamera/framebuffer.cpp
index baa298a8e3..55ca24c8a3 100644
--- a/src/libcamera/framebuffer.cpp
+++ b/src/libcamera/framebuffer.cpp
@@ -191,9 +191,7 @@ FrameBuffer::Private::~Private()
  *
  * If buffer with a Fence completes with errors due to a failure in handling
  * the fence, applications are responsible for releasing the Fence before
- * calling Request::addBuffer() again.
- *
- * \sa Request::addBuffer()
+ * reusing the buffer.
  *
  * \return A const pointer to the Fence if any, nullptr otherwise
  */
@@ -203,15 +201,13 @@ FrameBuffer::Private::~Private()
  * \brief Move a \a fence in this buffer
  * \param[in] fence The Fence
  *
- * This function associates a Fence with this Framebuffer. The intended caller
- * is the Request::addBuffer() function.
+ * This function associates a Fence with this Framebuffer. It is only intended
+ * to be called by the libcamera core.
  *
  * Once a FrameBuffer is associated with a Fence, the FrameBuffer will only be
  * made available to the hardware device once the Fence has been correctly
  * signalled.
  *
- * \sa Request::prepare()
- *
  * If the FrameBuffer completes successfully the core releases the Fence and the
  * Buffer can be reused immediately. If handling of the Fence fails during the
  * request preparation, the Fence is not released and is left in the
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index 54ef8296a4..29a21a0d70 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -7,7 +7,6 @@
 
 #include "libcamera/internal/pipeline_handler.h"
 
-#include <chrono>
 #include <sys/stat.h>
 #include <sys/sysmacros.h>
 
@@ -443,25 +442,6 @@ bool PipelineHandler::hasPendingRequests(const Camera *camera) const
 	return !camera->_d()->queuedRequests_.empty();
 }
 
-/**
- * \fn PipelineHandler::registerRequest()
- * \brief Register a request for use by the pipeline handler
- * \param[in] request The request to register
- *
- * This function is called when the request is created, and allows the pipeline
- * handler to perform any one-time initialization it requries for the request.
- */
-void PipelineHandler::registerRequest(Request *request)
-{
-	/*
-	 * Connect the request prepared signal to notify the pipeline handler
-	 * when a request is ready to be processed.
-	 */
-	request->_d()->prepared.connect(this, [this, request]() {
-		doQueueRequests(request->_d()->camera());
-	});
-}
-
 /**
  * \fn PipelineHandler::queueRequest()
  * \brief Queue a request
@@ -493,7 +473,7 @@ void PipelineHandler::queueRequest(Request *request)
 	Camera::Private *data = camera->_d();
 	data->waitingRequests_.push(request);
 
-	request->_d()->prepare(300ms);
+	doQueueRequests(camera);
 }
 
 /**
@@ -533,8 +513,6 @@ void PipelineHandler::doQueueRequests(Camera *camera)
 			break;
 
 		Request *request = data->waitingRequests_.front();
-		if (!request->_d()->prepared_)
-			break;
 
 		/*
 		 * Pop the request first, in case doQueueRequests() is called
diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp
index 8a3934add3..8819ba0ce3 100644
--- a/src/libcamera/request.cpp
+++ b/src/libcamera/request.cpp
@@ -7,7 +7,6 @@
 
 #include "libcamera/internal/request.h"
 
-#include <map>
 #include <sstream>
 
 #include <libcamera/base/log.h>
@@ -155,8 +154,6 @@ void Request::Private::doCancelRequest()
 
 	cancelled_ = true;
 	pending_.clear();
-	notifiers_.clear();
-	timer_.reset();
 }
 
 /**
@@ -187,135 +184,7 @@ void Request::Private::reset()
 {
 	sequence_ = 0;
 	cancelled_ = false;
-	prepared_ = false;
 	pending_.clear();
-	notifiers_.clear();
-	timer_.reset();
-}
-
-/*
- * Helper function to save some lines of code and make sure prepared_ is set
- * to true before emitting the signal.
- */
-void Request::Private::emitPrepareCompleted()
-{
-	prepared_ = true;
-	prepared.emit();
-}
-
-/**
- * \brief Prepare the Request to be queued to the device
- * \param[in] timeout Optional expiration timeout
- *
- * Prepare a Request to be queued to the hardware device by ensuring it is
- * ready for the incoming memory transfers.
- *
- * This currently means waiting on each frame buffer acquire fence to be
- * signalled. An optional expiration timeout can be specified. If not all the
- * fences have been signalled correctly before the timeout expires the Request
- * is cancelled.
- *
- * The function immediately emits the prepared signal if all the prepare
- * operations have been completed synchronously. If instead the prepare
- * operations require to wait the completion of asynchronous events, such as
- * fences notifications or timer expiration, the prepared signal is emitted upon
- * the asynchronous event completion.
- *
- * As we currently only handle fences, the function emits the prepared signal
- * immediately if there are no fences to wait on. Otherwise the prepared signal
- * is emitted when all fences have been signalled or the optional timeout has
- * expired.
- *
- * If not all the fences have been correctly signalled or the optional timeout
- * has expired the Request will be cancelled and the Request::prepared signal
- * emitted.
- *
- * The intended user of this function is the PipelineHandler base class, which
- * 'prepares' a Request before queuing it to the hardware device.
- */
-void Request::Private::prepare(std::chrono::milliseconds timeout)
-{
-	/* Create and connect one notifier for each synchronization fence. */
-	for (FrameBuffer *buffer : pending_) {
-		const Fence *fence = buffer->_d()->fence();
-		if (!fence)
-			continue;
-
-		auto [it, inserted] = notifiers_.try_emplace(buffer, fence->fd().get(), EventNotifier::Type::Read);
-		ASSERT(inserted);
-
-		it->second.activated.connect(this, [this, buffer] {
-			notifierActivated(buffer);
-		});
-	}
-
-	if (notifiers_.empty()) {
-		emitPrepareCompleted();
-		return;
-	}
-
-	/*
-	 * In case a timeout is specified, create a timer and set it up.
-	 *
-	 * The timer must be created here instead of in the Request constructor,
-	 * in order to be bound to the pipeline handler thread.
-	 */
-	if (timeout != 0ms) {
-		timer_ = std::make_unique<Timer>();
-		timer_->timeout.connect(this, &Request::Private::timeout);
-		timer_->start(timeout);
-	}
-}
-
-/**
- * \var Request::Private::prepared
- * \brief Request preparation completed Signal
- *
- * The signal is emitted once the request preparation has completed and is ready
- * to be queued. The Request might complete with errors in which case it is
- * cancelled.
- *
- * The intended slot for this signal is the PipelineHandler::doQueueRequests()
- * function which queues Request after they have been prepared or cancel them
- * if they have failed preparing.
- */
-
-void Request::Private::notifierActivated(FrameBuffer *buffer)
-{
-	/* Close the fence if successfully signalled. */
-	ASSERT(buffer);
-	buffer->releaseFence();
-
-	/* Remove the entry from the map and check if other fences are pending. */
-	auto it = notifiers_.find(buffer);
-	ASSERT(it != notifiers_.end());
-	notifiers_.erase(it);
-
-	Request *request = _o<Request>();
-	LOG(Request, Debug)
-		<< "Request " << request->cookie() << " buffer " << buffer
-		<< " fence signalled";
-
-	if (!notifiers_.empty())
-		return;
-
-	/* All fences completed, delete the timer and emit the prepared signal. */
-	timer_.reset();
-	emitPrepareCompleted();
-}
-
-void Request::Private::timeout()
-{
-	/* A timeout can only happen if there are fences not yet signalled. */
-	ASSERT(!notifiers_.empty());
-	notifiers_.clear();
-
-	Request *request = _o<Request>();
-	LOG(Request, Debug) << "Request prepare timeout: " << request->cookie();
-
-	cancel();
-
-	emitPrepareCompleted();
 }
 #endif /* __DOXYGEN_PUBLIC__ */
 
