diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index c5ef942ad73a77b2af23c4fa74dd8fa4259b5997..685c46e628993cf6548f45af4b5ba77ef75d4b44 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -43,6 +43,18 @@ config LOGO_PARISC_CLUT224
 	depends on PARISC
 	default y
 
+config LOGO_SECO_MEMLOGO
+	bool "Memory based dynamic logo"
+	depends on LOGO
+	depends on OF
+	default y
+	help
+	  Get logo from memory. Memory address and logo size are taken from
+	  a device tree node. Compatible should be "seco,memlogo".
+	  Address is set by "address", size - by "size".
+	  It is also necessary to reserve memory for logo via
+	  "reserved-memory" node in dtb.
+
 config LOGO_SGI_CLUT224
 	bool "224-color SGI Linux logo"
 	depends on SGI_IP22 || SGI_IP27 || SGI_IP32
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index 59b0bc8f4f334fc4a9012dd4c8053ba3b758b969..40623314604d3ff97ee412259b84401461128110 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -18,6 +18,10 @@
 #include <asm/setup.h>
 #endif
 
+#ifdef CONFIG_LOGO_SECO_MEMLOGO
+#include <linux/of.h>
+#endif
+
 static bool nologo;
 module_param(nologo, bool, 0);
 MODULE_PARM_DESC(nologo, "Disables startup logo");
@@ -44,6 +48,19 @@ late_initcall_sync(fb_logo_late_init);
 const struct linux_logo * __ref fb_find_logo(int depth)
 {
 	const struct linux_logo *logo = NULL;
+#ifdef CONFIG_LOGO_SECO_MEMLOGO
+	u32 logophys = 0;
+	u32 logosize = 0;
+
+	const char *compatible = "seco,memlogo";
+	struct device_node *np;
+	int ret;
+
+	struct linux_logo *validate_logo = NULL;
+	unsigned int logo_bpc;
+	unsigned int logo_size_validate;
+	unsigned int logo_data_size;
+#endif
 
 	if (nologo || logos_freed)
 		return NULL;
@@ -112,6 +129,64 @@ const struct linux_logo * __ref fb_find_logo(int depth)
 		/* EDGEHOG OS logo */
 		logo = &logo_edgehog_clut224;
 #endif
+#ifdef CONFIG_LOGO_SECO_MEMLOGO
+		np = of_find_compatible_node(NULL, NULL, compatible);
+		if (!np)
+			pr_warn("memlogo: Couldn't find node: %s\n", compatible);
+		else {
+			ret = of_property_read_u32(np, "address", &logophys);
+			if (ret)
+				pr_warn("memlogo: address is not found in device tree\n");
+			ret = of_property_read_u32(np, "size", &logosize);
+			if (ret)
+				pr_warn("memlogo: size is not found in device tree\n");
+		}
+		of_node_put(np);
+
+		if (logophys && logosize) {
+			validate_logo = phys_to_virt(logophys);
+
+			if (validate_logo->type < LINUX_LOGO_MONO ||
+			    validate_logo->type > LINUX_LOGO_GRAY256)
+				return logo;
+
+			switch (validate_logo->type) {
+			case LINUX_LOGO_MONO:
+				logo_bpc = 1;
+				break;
+			case LINUX_LOGO_VGA16:
+				logo_bpc = 4;
+				break;
+			case LINUX_LOGO_CLUT224:
+				fallthrough;
+			case LINUX_LOGO_GRAY256:
+				logo_bpc = 8;
+				break;
+			}
+
+			logo_data_size = DIV_ROUND_UP(validate_logo->width *
+						      validate_logo->height *
+						      logo_bpc, 8);
+
+			logo_size_validate = sizeof(struct linux_logo);
+			logo_size_validate += logo_data_size;
+			logo_size_validate += validate_logo->clutsize;
+			if (logosize < logo_size_validate) {
+				pr_err("memlogo: logo size is too big. Need to reserve more memory for logo in DT\n");
+				return logo;
+			}
+
+			if (logosize < logo_data_size + (uint32_t)validate_logo->data)
+				return logo;
+			if (validate_logo->type == LINUX_LOGO_CLUT224 &&
+			    logosize < validate_logo->clutsize + (uint32_t)validate_logo->clut)
+				return logo;
+
+			validate_logo->data += (size_t)validate_logo;
+			validate_logo->clut += (size_t)validate_logo;
+			logo = validate_logo;
+		}
+#endif
 
 	}
 	return logo;