diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig
index db51386c663a..45dc4b2935e7 100644
--- a/drivers/cache/Kconfig
+++ b/drivers/cache/Kconfig
@@ -1,6 +1,12 @@
 # SPDX-License-Identifier: GPL-2.0
 menu "Cache Drivers"
 
+config CACHE_COHERENCY_CLASS
+	bool "Cache coherency control class"
+	help
+	  Class to which coherency control drivers register allowing core kernel
+	  subsystems to issue invalidations and similar coherency operations.
+
 config AX45MP_L2_CACHE
 	bool "Andes Technology AX45MP L2 Cache controller"
 	depends on RISCV
diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile
index 55c5e851034d..b72b20f4248f 100644
--- a/drivers/cache/Makefile
+++ b/drivers/cache/Makefile
@@ -3,3 +3,5 @@
 obj-$(CONFIG_AX45MP_L2_CACHE)		+= ax45mp_cache.o
 obj-$(CONFIG_SIFIVE_CCACHE)		+= sifive_ccache.o
 obj-$(CONFIG_STARFIVE_STARLINK_CACHE)	+= starfive_starlink_cache.o
+
+obj-$(CONFIG_CACHE_COHERENCY_CLASS)	+= coherency_core.o
diff --git a/drivers/cache/coherency_core.c b/drivers/cache/coherency_core.c
new file mode 100644
index 000000000000..52cb4ceae00c
--- /dev/null
+++ b/drivers/cache/coherency_core.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Class to manage OS controlled coherency agents within the system.
+ * Specifically to enable operations such as write back and invalidate.
+ *
+ * Copyright: Huawei 2025
+ * Some elements based on fwctl class as an example of a modern
+ * lightweight class.
+ */
+
+#include <linux/cache_coherency.h>
+#include <linux/container_of.h>
+#include <linux/idr.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <asm/cacheflush.h>
+
+static DEFINE_IDA(cache_coherency_ida);
+
+static void cache_coherency_device_release(struct device *device)
+{
+	struct cache_coherency_device *ccd =
+		container_of(device, struct cache_coherency_device, dev);
+
+	ida_free(&cache_coherency_ida, ccd->id);
+}
+
+static struct class cache_coherency_class = {
+	.name = "cache_coherency",
+	.dev_release = cache_coherency_device_release,
+};
+
+static int cache_inval_one(struct device *dev, void *data)
+{
+	struct cache_coherency_device *ccd =
+		container_of(dev, struct cache_coherency_device, dev);
+
+	if (!ccd->ops)
+		return -EINVAL;
+
+	return ccd->ops->wbinv(ccd, data);
+}
+
+static int cache_inval_done_one(struct device *dev, void *data)
+{
+	struct cache_coherency_device *ccd =
+		container_of(dev, struct cache_coherency_device, dev);
+	if (!ccd->ops)
+		return -EINVAL;
+
+	return ccd->ops->done(ccd);
+}
+
+static int cache_invalidate_memregion(int res_desc,
+				      phys_addr_t addr, size_t size)
+{
+	int ret;
+	struct cc_inval_params params = {
+		.addr = addr,
+		.size = size,
+	};
+
+	ret = class_for_each_device(&cache_coherency_class, NULL, &params,
+				    cache_inval_one);
+	if (ret)
+		return ret;
+
+	return class_for_each_device(&cache_coherency_class, NULL, NULL,
+				     cache_inval_done_one);
+}
+
+static const struct system_cache_flush_method cache_flush_method = {
+	.invalidate_memregion = cache_invalidate_memregion,
+};
+
+struct cache_coherency_device *
+_cache_coherency_alloc_device(struct device *parent,
+			      const struct coherency_ops *ops, size_t size)
+{
+
+	if (!ops || !ops->wbinv)
+		return NULL;
+
+	struct cache_coherency_device *ccd __free(kfree) = kzalloc(size, GFP_KERNEL);
+
+	if (!ccd)
+		return NULL;
+
+	ccd->dev.class = &cache_coherency_class;
+	ccd->dev.parent = parent;
+	ccd->ops = ops;
+	ccd->id = ida_alloc(&cache_coherency_ida, GFP_KERNEL);
+
+	if (dev_set_name(&ccd->dev, "cache_coherency%d", ccd->id))
+		return NULL;
+
+ 	device_initialize(&ccd->dev);
+
+	return_ptr(ccd);
+}
+EXPORT_SYMBOL_NS_GPL(_cache_coherency_alloc_device, "CACHE_COHERENCY");
+
+int cache_coherency_device_register(struct cache_coherency_device *ccd)
+{
+	return device_add(&ccd->dev);
+}
+EXPORT_SYMBOL_NS_GPL(cache_coherency_device_register, "CACHE_COHERENCY");
+
+void cache_coherency_device_unregister(struct cache_coherency_device *ccd)
+{
+	device_del(&ccd->dev);
+}
+EXPORT_SYMBOL_NS_GPL(cache_coherency_device_unregister, "CACHE_COHERENCY");
+
+static int __init cache_coherency_init(void)
+{
+	int ret;
+
+	ret = class_register(&cache_coherency_class);
+	if (ret)
+		return ret;
+
+	//TODO: generalize
+	arm64_set_sys_cache_flush_method(&cache_flush_method);
+
+	return 0;
+}
+subsys_initcall(cache_coherency_init);
diff --git a/include/linux/cache_coherency.h b/include/linux/cache_coherency.h
new file mode 100644
index 000000000000..d49be27ad4f1
--- /dev/null
+++ b/include/linux/cache_coherency.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Cache coherency device drivers
+ *
+ * Copyright Huawei 2025
+ */
+#ifndef _LINUX_CACHE_COHERENCY_H_
+#define _LINUX_CACHE_COHERENCY_H_
+
+#include <linux/cleanup.h>
+#include <linux/device.h>
+
+struct cache_coherency_device;
+struct cc_inval_params {
+	phys_addr_t addr;
+	size_t size;
+};
+struct coherency_ops {
+	int (*wbinv)(struct cache_coherency_device *ccd, struct cc_inval_params *invp);
+	int (*done)(struct cache_coherency_device *ccd);
+};
+
+struct cache_coherency_device {
+	struct device dev;
+	const struct coherency_ops *ops;
+	int id;
+};
+
+int cache_coherency_device_register(struct cache_coherency_device *ccd);
+void cache_coherency_device_unregister(struct cache_coherency_device *ccd);
+
+struct cache_coherency_device *
+_cache_coherency_alloc_device(struct device *parent,
+			      const struct coherency_ops *ops, size_t size);
+
+#define cache_coherency_alloc_device(parent, ops, drv_struct, member)		\
+	({									\
+		static_assert(__same_type(struct cache_coherency_device,	\
+					  ((drv_struct *)NULL)->member));	\
+		static_assert(offsetof(drv_struct, member) == 0);		\
+		(drv_struct *)_cache_coherency_alloc_device(parent, ops,	\
+							sizeof(drv_struct));	\
+	})
+
+static inline struct cache_coherency_device *
+	cache_coherency_device_get(struct cache_coherency_device *ccd)
+{
+	get_device(&ccd->dev);
+	return ccd;
+}
+
+static inline void cache_coherency_device_put(struct cache_coherency_device *ccd)
+{
+	put_device(&ccd->dev);
+}
+
+DEFINE_FREE(cache_coherency_device, struct cache_coherency_device *,
+	    if (_T) cache_coherency_device_put(_T));
+
+#endif
