diff --git a/fs/vfs.c b/fs/vfs.c
index e05a02ad5b0..f06844f2a33 100644
--- a/fs/vfs.c
+++ b/fs/vfs.c
@@ -331,6 +331,41 @@ void vfs_print_mounts(void)
 	}
 }
 
+int vfs_open_file(const char *path, enum dir_open_flags_t oflags,
+		  struct udevice **filp)
+{
+	struct udevice *vfs, *mnt, *dir;
+	const char *subpath, *leaf;
+	struct vfsmount *mnt_priv;
+	char *dirpath;
+	int ret;
+
+	vfs = vfs_root();
+	if (!vfs)
+		return log_msg_ret("voi", -ENXIO);
+
+	ret = vfs_find_mount(vfs, path, &mnt, &subpath);
+	if (ret)
+		return log_msg_ret("vom", ret);
+
+	mnt_priv = dev_get_uclass_priv(mnt);
+
+	ret = fs_split_path(subpath, &dirpath, &leaf);
+	if (ret)
+		return log_msg_ret("vos", ret);
+
+	ret = fs_lookup_dir(mnt_priv->target, dirpath, &dir);
+	free(dirpath);
+	if (ret)
+		return log_msg_ret("vod", ret);
+
+	ret = dir_open_file(dir, leaf, oflags, filp);
+	if (ret)
+		return log_msg_ret("vof", ret);
+
+	return 0;
+}
+
 int vfs_ls(const char *path)
 {
 	struct udevice *vfs, *mnt, *dir = NULL;
diff --git a/include/vfs.h b/include/vfs.h
index f85f45da4dd..53d1932e861 100644
--- a/include/vfs.h
+++ b/include/vfs.h
@@ -11,6 +11,8 @@
 #ifndef __VFS_H
 #define __VFS_H
 
+#include <dir.h>
+
 struct udevice;
 
 /**
@@ -136,4 +138,18 @@ void vfs_print_mounts(void);
  */
 int vfs_ls(const char *path);
 
+/**
+ * vfs_open_file() - Open a file by absolute VFS path
+ *
+ * Resolves the path through the mount tree, splits into directory and leaf,
+ * then opens the file.
+ *
+ * @path: Absolute VFS path to the file
+ * @oflags: Open flags (DIR_O_RDONLY, DIR_O_WRONLY, DIR_O_RDWR)
+ * @filp: Returns the UCLASS_FILE device
+ * Return: 0 if OK, -ve on error
+ */
+int vfs_open_file(const char *path, enum dir_open_flags_t oflags,
+		  struct udevice **filp);
+
 #endif
