diff --git a/src/ipa/ipu3/algorithms/blc.cpp b/src/ipa/ipu3/algorithms/blc.cpp
new file mode 100644
index 00000000..df56e292
--- /dev/null
+++ b/src/ipa/ipu3/algorithms/blc.cpp
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2021, Google inc.
+ *
+ * blc.cpp - IPU3 Black Level Correction control
+ */
+
+#include "blc.h"
+
+#include <string.h>
+
+/**
+ * \file blc.h
+ */
+
+namespace libcamera {
+
+namespace ipa::ipu3::algorithms {
+
+/**
+ * \class BlackLevelCorrection
+ * \brief A class to handle optical black correction
+ *
+ * The pixels output by the camera normally include a black level, because
+ * sensors do not always report a signal level of '0' for black. Pixels at or
+ * below this level should be considered black. To achieve that, the ImgU BLC
+ * algorithm subtracts a configurable offset from all pixels.
+ *
+ * The black level can be measured at runtime from an optical dark region of the
+ * camera sensor, or measured during the camera tuning process. The first option
+ * isn't currently supported.
+ */
+
+BlackLevelCorrection::BlackLevelCorrection()
+{
+}
+
+/**
+ * \brief Fill in the parameter structure, and enable optical black correction
+ * \param context The shared IPA context
+ * \param params The IPU3 parameters
+ *
+ * Populate the IPU3 parameter structure with the correction values for each
+ * channel and enable the corresponding ImgU block processing.
+ */
+void BlackLevelCorrection::prepare([[maybe_unused]] IPAContext &context,
+			      ipu3_uapi_params *params)
+{
+	/*
+	 * The Optical Black Level correction values
+	 * \todo The correction values should come from sensor specific
+	 * tuning processes. This is a first rough approximation
+	 */
+	params->obgrid_param.gr = 64;
+	params->obgrid_param.r  = 64;
+	params->obgrid_param.b  = 64;
+	params->obgrid_param.gb = 64;
+
+	/* Enable the custom optical black correction processing */
+	params->use.obgrid = 1;
+	params->use.obgrid_param = 1;
+}
+
+} /* namespace ipa::ipu3::algorithms */
+
+} /* namespace libcamera */
diff --git a/src/ipa/ipu3/algorithms/blc.h b/src/ipa/ipu3/algorithms/blc.h
new file mode 100644
index 00000000..4b7cb483
--- /dev/null
+++ b/src/ipa/ipu3/algorithms/blc.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2021, Google inc.
+ *
+ * black_correction.h - IPU3 Black Level Correction control
+ */
+#ifndef __LIBCAMERA_IPU3_ALGORITHMS_BLC_H__
+#define __LIBCAMERA_IPU3_ALGORITHMS_BLC_H__
+
+#include "algorithm.h"
+
+namespace libcamera {
+
+namespace ipa::ipu3::algorithms {
+
+class BlackLevelCorrection : public Algorithm
+{
+public:
+	BlackLevelCorrection();
+
+	void prepare(IPAContext &context, ipu3_uapi_params *params) override;
+};
+
+} /* namespace ipa::ipu3::algorithms */
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_IPU3_ALGORITHMS_BLC_H__ */
diff --git a/src/ipa/ipu3/algorithms/meson.build b/src/ipa/ipu3/algorithms/meson.build
index deae225b..3ec42f72 100644
--- a/src/ipa/ipu3/algorithms/meson.build
+++ b/src/ipa/ipu3/algorithms/meson.build
@@ -4,5 +4,6 @@ ipu3_ipa_algorithms = files([
     'agc.cpp',
     'algorithm.cpp',
     'awb.cpp',
+    'blc.cpp',
     'tone_mapping.cpp',
 ])
diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
index 06f53fbe..6d9bbf39 100644
--- a/src/ipa/ipu3/ipu3.cpp
+++ b/src/ipa/ipu3/ipu3.cpp
@@ -33,6 +33,7 @@
 #include "algorithms/agc.h"
 #include "algorithms/algorithm.h"
 #include "algorithms/awb.h"
+#include "algorithms/blc.h"
 #include "algorithms/tone_mapping.h"
 #include "libipa/camera_sensor_helper.h"
 
@@ -282,6 +283,7 @@ int IPAIPU3::init(const IPASettings &settings,
 	/* Construct our Algorithms */
 	algorithms_.push_back(std::make_unique<algorithms::Agc>());
 	algorithms_.push_back(std::make_unique<algorithms::Awb>());
+	algorithms_.push_back(std::make_unique<algorithms::BlackLevelCorrection>());
 	algorithms_.push_back(std::make_unique<algorithms::ToneMapping>());
 
 	return 0;
