diff --git a/include/libcamera/internal/converter/converter_dw100.h b/include/libcamera/internal/converter/converter_dw100.h
index dc41f365..a3062e84 100644
--- a/include/libcamera/internal/converter/converter_dw100.h
+++ b/include/libcamera/internal/converter/converter_dw100.h
@@ -19,6 +19,11 @@ class ConverterDW100 : public V4L2M2MConverter
 {
 public:
 	ConverterDW100(std::shared_ptr<MediaDevice> media);
+
+	int applyMappings(const Stream *stream);
+
+private:
+	int loadDewarpMaps();
 };
 
 } /* namespace libcamera */
diff --git a/src/libcamera/converter/converter_dw100.cpp b/src/libcamera/converter/converter_dw100.cpp
index 3061fc71..1a641779 100644
--- a/src/libcamera/converter/converter_dw100.cpp
+++ b/src/libcamera/converter/converter_dw100.cpp
@@ -7,12 +7,17 @@
 
 #include "libcamera/internal/converter/converter_dw100.h"
 
+#include <linux/dw100.h>
+
+#include <libcamera/base/file.h>
 #include <libcamera/base/log.h>
 
+#include <libcamera/stream.h>
 #include <libcamera/geometry.h>
 
 #include "libcamera/internal/media_device.h"
 #include "libcamera/internal/v4l2_videodevice.h"
+#include "libcamera/internal/yaml_parser.h"
 
 namespace libcamera {
 
@@ -32,6 +37,128 @@ LOG_DECLARE_CATEGORY(Converter)
 ConverterDW100::ConverterDW100(std::shared_ptr<MediaDevice> media)
 	: V4L2M2MConverter(media.get(), Feature::Crop)
 {
+	loadDewarpMaps();
+}
+
+int ConverterDW100::loadDewarpMaps()
+{
+	int ret;
+
+	char const *configFromEnv = utils::secure_getenv("LIBCAMERA_DEWARP_CONFIG_FILE");
+	if (!configFromEnv || *configFromEnv == '\0')
+		return 0;
+
+	LOG(Converter, Info) << "Parsing dewarp configuration file " << configFromEnv;
+
+	std::string filename = std::string(configFromEnv);
+	File file(filename);
+
+	if (!file.open(File::OpenModeFlag::ReadOnly)) {
+		ret = file.error();
+		LOG(Converter, Error) << "Failed to open configuration file "
+				      << filename << ": " << strerror(-ret);
+		return ret;
+	}
+
+	std::unique_ptr<libcamera::YamlObject> data = YamlParser::parse(file);
+	if (!data)
+		return -EINVAL;
+
+	if (!data->contains("mappings")) {
+		LOG(Converter, Error) << "Vertex mapping key missing";
+		return -EINVAL;
+	}
+
+	const YamlObject &mappings = (*data)["mappings"];
+	if (!mappings.isList() || mappings.size() == 0) {
+		LOG(Converter, Error) << "Invalid mappings entry";
+		return -EINVAL;
+	}
+
+	LOG(Converter, Debug) << "Parsing " << mappings.size() << " mappings";
+	mappings_.clear();
+	mappings_.reserve(mappings.size());
+
+	for (std::size_t i = 0; i < mappings.size(); i++) {
+		const YamlObject &mapping = mappings[i];
+		if (!mapping.isDictionary()) {
+			LOG(Converter, Error) << "Mapping is not a dictionary";
+			return -EINVAL;
+		}
+
+		if (!mapping.contains("input-resolution")) {
+			LOG(Converter, Error) << "Input resolution missing";
+			return -EINVAL;
+		}
+
+		if (!mapping.contains("output-resolution")) {
+			LOG(Converter, Error) << "Output resolution missing";
+			return -EINVAL;
+		}
+
+		if (!mapping.contains("mapping")) {
+			LOG(Converter, Error) << "Mapping table missing";
+			return -EINVAL;
+		}
+
+		const YamlObject &input_res = mapping["input-resolution"];
+		if (!input_res.isList() || input_res.size() != 2) {
+			LOG(Converter, Error) << "Incorrect input resolution";
+			return -EINVAL;
+		}
+
+		const YamlObject &output_res = mapping["output-resolution"];
+		if (!output_res.isList() || output_res.size() != 2) {
+			LOG(Converter, Error) << "Incorrect output resolution";
+			return -EINVAL;
+		}
+
+		const YamlObject &map = mapping["mapping"];
+		if (!map.isList() || map.size() == 0) {
+			LOG(Converter, Error) << "Incorrect mapping entries";
+			return -EINVAL;
+		}
+
+		Size input(input_res[0].get<uint32_t>(0), input_res[1].get<uint32_t>(0));
+		Size output(output_res[0].get<uint32_t>(0), output_res[1].get<uint32_t>(0));
+		const auto &mapVector = map.getList<uint32_t>().value_or(std::vector<uint32_t>{});
+
+		LOG(Converter, Debug)
+			<< "Input/Output mapping resolution " << input << " -> " << output;
+
+		mappings_.emplace_back(Mapping(input, output, mapVector));
+	}
+
+	return mappings.size();
+}
+
+/*
+ * \brief Apply
+ * \todo this is just a wrapper, trying to test waters
+ * \param[in] media The media device implementing the converter
+ */
+int ConverterDW100::applyMappings(const Stream *stream)
+{
+	const StreamConfiguration &config = stream->configuration();
+	ControlList ctrls;
+	int ret = 0;
+
+	for (const auto &map : mappings_) {
+		/* Currently DW100's input and output configuration are same. */
+		if (map.inputSize() == config.size &&
+		    map.outputSize() == config.size) {
+			auto value = Span<const int32_t>(reinterpret_cast<const int32_t *>(map.mapping()), map.size());
+
+			ControlValue c(value);
+			ctrls.set(V4L2_CID_DW100_DEWARPING_16x16_VERTEX_MAP, c);
+			ret = applyControls(stream, ctrls);
+
+			LOG(Converter, Debug) << "Dewarp mapping applied for " << config.toString();
+			break;
+		}
+	}
+
+       return ret;
 }
 
 } /* namespace libcamera */
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index 881e10e1..f102b364 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -1019,6 +1019,10 @@ int PipelineHandlerRkISP1::start(Camera *camera, [[maybe_unused]] const ControlL
 				LOG(RkISP1, Error) << "Failed to start dewarper";
 				return ret;
 			}
+
+			ret = dewarper_->applyMappings(&data->mainPathStream_);
+			if (ret)
+				LOG(RkISP1, Warning) << "Dewarper mapping couldn't be applied";
 		}
 	}
 
