aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNaoto Yamaguchi <naoto.yamaguchi@aisin.co.jp>2023-04-23 20:25:45 +0900
committerNaoto Yamaguchi <naoto.yamaguchi@aisin.co.jp>2023-05-09 08:13:10 +0900
commitb3e49987c5706612ee342c685dea799be596df6a (patch)
tree7c4e724755638a387fa7bf555e050f59be81fbbe
parenta070ad4db8e4a35fc34b0610b56dcfc1e2caaad3 (diff)
Enable drm-lease support at psplash
The upstream version of psplash is supporting fb based splash screen. On the other hand, drm lease infrastructure is not support fb. This patch enable drm-lease support at psplash. This work contributed by Hiroyuki Ishii at CES2023 demo development. Bug-AGL: SPEC-4766 Change-Id: I50b382c7f8ca4b46a8fb06fd649d0cfa49800c6d Signed-off-by: Naoto Yamaguchi <naoto.yamaguchi@aisin.co.jp>
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0001-Fix-duplicated-definition-of-bool.patch35
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0002-Trim-trailing-spaces.patch535
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0003-Fix-unused-result-warnings.patch150
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0004-Remove-unused-save_termios.patch41
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0005-Remove-psplash-fb.h-from-psplash.h.patch81
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0006-Extract-plot-pixel-from-psplash-fb.patch624
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0007-Extract-draw-rect-image-from-psplash-fb.patch299
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0008-Extract-draw-font-from-psplash-fb.patch350
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0009-psplash.c-Make-psplash_draw_-msg-progress-independen.patch191
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0010-Rework-flip-as-function-pointer.patch141
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0011-Import-drm-howto-modeset.c-as-psplash-drm.c.patch764
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0012-Implement-drm-backend.patch507
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0013-Reverse-modeset_list.patch48
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0014-psplash-drm.c-Allocate-resources-only-for-the-first-.patch46
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch350
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0016-Imprement-drm-lease-support.patch189
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0017-drm-lease-Fix-incorrect-drawing-with-portrait-orient.patch42
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/psplash_git.bbappend43
18 files changed, 4436 insertions, 0 deletions
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0001-Fix-duplicated-definition-of-bool.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0001-Fix-duplicated-definition-of-bool.patch
new file mode 100644
index 00000000..ae533b73
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0001-Fix-duplicated-definition-of-bool.patch
@@ -0,0 +1,35 @@
+From 816b7168c6380ec5a72416d3e0c52e22d891e2d9 Mon Sep 17 00:00:00 2001
+From: Hiroyuki Ishii <ishii.hiroyuki002@jp.panasonic.com>
+Date: Tue, 27 Dec 2022 14:44:14 +0900
+Subject: [PATCH 01/17] Fix duplicated definition of bool
+
+We'd like to use stdbool.h instead of defining bool type
+duplicatedly to avoid build issue in future changes.
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Hiroyuki Ishii <ishii.hiroyuki002@jp.panasonic.com>
+---
+ psplash.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/psplash.h b/psplash.h
+index 1c42ec7..9be44ba 100644
+--- a/psplash.h
++++ b/psplash.h
+@@ -34,10 +34,10 @@
+ #include <sys/types.h>
+ #include <termios.h>
+ #include <unistd.h>
++#include <stdbool.h>
+
+ typedef uint8_t uint8;
+ typedef uint16_t uint16;
+-typedef int bool;
+
+ #ifndef FALSE
+ #define FALSE 0
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0002-Trim-trailing-spaces.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0002-Trim-trailing-spaces.patch
new file mode 100644
index 00000000..2980809e
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0002-Trim-trailing-spaces.patch
@@ -0,0 +1,535 @@
+From 5f82ef966776c9520af8ca59d12260d7e908e464 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:41 +0300
+Subject: [PATCH 02/17] Trim trailing spaces
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ psplash-console.c | 34 +++++++++++-----------
+ psplash-console.h | 8 ++---
+ psplash-fb.c | 4 +--
+ psplash-fb.h | 34 +++++++++++-----------
+ psplash-write.c | 14 ++++-----
+ psplash.c | 74 +++++++++++++++++++++++------------------------
+ psplash.h | 4 +--
+ 7 files changed, 86 insertions(+), 86 deletions(-)
+
+diff --git a/psplash-console.c b/psplash-console.c
+index 3a40620..c00c6fe 100644
+--- a/psplash-console.c
++++ b/psplash-console.c
+@@ -1,5 +1,5 @@
+-/*
+- * pslash - a lightweight framebuffer splashscreen for embedded devices.
++/*
++ * pslash - a lightweight framebuffer splashscreen for embedded devices.
+ *
+ * Copyright (c) 2006 Matthew Allum <mallum@o-hand.com>
+ *
+@@ -27,12 +27,12 @@ vt_request (int UNUSED(sig))
+ perror("Error cannot switch away from console");
+ Visible = 0;
+
+- /* FIXME:
+- * We likely now want to signal the main loop as to exit
++ /* FIXME:
++ * We likely now want to signal the main loop as to exit
+ * and we've now likely switched to the X tty. Note, this
+ * seems to happen anyway atm due to select() call getting
+ * a signal interuption error - not sure if this is really
+- * reliable however.
++ * reliable however.
+ */
+ }
+ else
+@@ -49,7 +49,7 @@ psplash_console_ignore_switches (void)
+ {
+ struct sigaction act;
+ struct vt_mode vt_mode;
+-
++
+ if (ioctl(ConsoleFd, VT_GETMODE, &vt_mode) < 0)
+ {
+ perror("Error VT_SETMODE failed");
+@@ -60,7 +60,7 @@ psplash_console_ignore_switches (void)
+ sigemptyset (&act.sa_mask);
+ act.sa_flags = 0;
+ sigaction (SIGUSR1, &act, 0);
+-
++
+ vt_mode.mode = VT_AUTO;
+ vt_mode.relsig = 0;
+ vt_mode.acqsig = 0;
+@@ -74,7 +74,7 @@ psplash_console_handle_switches (void)
+ {
+ struct sigaction act;
+ struct vt_mode vt_mode;
+-
++
+ if (ioctl(ConsoleFd, VT_GETMODE, &vt_mode) < 0)
+ {
+ perror("Error VT_SETMODE failed");
+@@ -85,7 +85,7 @@ psplash_console_handle_switches (void)
+ sigemptyset (&act.sa_mask);
+ act.sa_flags = 0;
+ sigaction (SIGUSR1, &act, 0);
+-
++
+ vt_mode.mode = VT_PROCESS;
+ vt_mode.relsig = SIGUSR1;
+ vt_mode.acqsig = SIGUSR1;
+@@ -94,8 +94,8 @@ psplash_console_handle_switches (void)
+ perror("Error VT_SETMODE failed");
+ }
+
+-void
+-psplash_console_switch (void)
++void
++psplash_console_switch (void)
+ {
+ char vtname[10];
+ int fd;
+@@ -114,9 +114,9 @@ psplash_console_switch (void)
+ close(fd);
+ return;
+ }
+-
++
+ close(fd);
+-
++
+ sprintf(vtname,"/dev/tty%d", VTNum);
+
+ if ((ConsoleFd = open(vtname, O_RDWR|O_NDELAY, 0)) < 0)
+@@ -134,12 +134,12 @@ psplash_console_switch (void)
+
+ if (ioctl(ConsoleFd, VT_ACTIVATE, VTNum) != 0)
+ perror("Error VT_ACTIVATE failed");
+-
++
+ if (ioctl(ConsoleFd, VT_WAITACTIVE, VTNum) != 0)
+ perror("Error VT_WAITACTIVE failed\n");
+
+ psplash_console_handle_switches ();
+-
++
+ if (ioctl(ConsoleFd, KDSETMODE, KD_GRAPHICS) < 0)
+ perror("Error KDSETMODE KD_GRAPHICS failed\n");
+
+@@ -156,7 +156,7 @@ psplash_console_reset (void)
+ return;
+
+ /* Back to text mode */
+- ioctl(ConsoleFd, KDSETMODE, KD_TEXT);
++ ioctl(ConsoleFd, KDSETMODE, KD_TEXT);
+
+ psplash_console_ignore_switches ();
+
+@@ -175,7 +175,7 @@ psplash_console_reset (void)
+
+ /* Cleanup */
+
+- close(ConsoleFd);
++ close(ConsoleFd);
+
+ if ((fd = open ("/dev/tty0", O_RDWR|O_NDELAY, 0)) >= 0)
+ {
+diff --git a/psplash-console.h b/psplash-console.h
+index c893bf2..ad51ef2 100644
+--- a/psplash-console.h
++++ b/psplash-console.h
+@@ -1,5 +1,5 @@
+-/*
+- * pslash - a lightweight framebuffer splashscreen for embedded devices.
++/*
++ * pslash - a lightweight framebuffer splashscreen for embedded devices.
+ *
+ * Copyright (c) 2006 Matthew Allum <mallum@o-hand.com>
+ *
+@@ -10,8 +10,8 @@
+ #ifndef _HAVE_PSPLASH_CONSOLE_H
+ #define _HAVE_PSPLASH_CONSOLE_H
+
+-void
+-psplash_console_switch (void);
++void
++psplash_console_switch (void);
+
+ void
+ psplash_console_reset (void);
+diff --git a/psplash-fb.c b/psplash-fb.c
+index 2babb5f..1d2d7db 100644
+--- a/psplash-fb.c
++++ b/psplash-fb.c
+@@ -429,13 +429,13 @@ psplash_fb_plot_pixel (PSplashFB *fb,
+ {
+ case 32:
+ *(volatile uint32_t *) (fb->bdata + off)
+- = ((red >> (8 - fb->red_length)) << fb->red_offset)
++ = ((red >> (8 - fb->red_length)) << fb->red_offset)
+ | ((green >> (8 - fb->green_length)) << fb->green_offset)
+ | ((blue >> (8 - fb->blue_length)) << fb->blue_offset);
+ break;
+ case 16:
+ *(volatile uint16_t *) (fb->bdata + off)
+- = ((red >> (8 - fb->red_length)) << fb->red_offset)
++ = ((red >> (8 - fb->red_length)) << fb->red_offset)
+ | ((green >> (8 - fb->green_length)) << fb->green_offset)
+ | ((blue >> (8 - fb->blue_length)) << fb->blue_offset);
+ break;
+diff --git a/psplash-fb.h b/psplash-fb.h
+index 16e2b20..eafa293 100644
+--- a/psplash-fb.h
++++ b/psplash-fb.h
+@@ -1,5 +1,5 @@
+-/*
+- * pslash - a lightweight framebuffer splashscreen for embedded devices.
++/*
++ * pslash - a lightweight framebuffer splashscreen for embedded devices.
+ *
+ * Copyright (c) 2006 Matthew Allum <mallum@o-hand.com>
+ *
+@@ -20,11 +20,11 @@ enum RGBMode {
+
+ typedef struct PSplashFB
+ {
+- int fd;
++ int fd;
+ struct fb_var_screeninfo fb_var;
+- struct termios save_termios;
+- int type;
+- int visual;
++ struct termios save_termios;
++ int type;
++ int visual;
+ int width, height;
+ int bpp;
+ int stride;
+@@ -56,20 +56,20 @@ PSplashFB*
+ psplash_fb_new (int angle, int fbdev_id);
+
+ void
+-psplash_fb_draw_rect (PSplashFB *fb,
+- int x,
+- int y,
+- int width,
++psplash_fb_draw_rect (PSplashFB *fb,
++ int x,
++ int y,
++ int width,
+ int height,
+ uint8 red,
+ uint8 green,
+ uint8 blue);
+
+ void
+-psplash_fb_draw_image (PSplashFB *fb,
+- int x,
+- int y,
+- int img_width,
++psplash_fb_draw_image (PSplashFB *fb,
++ int x,
++ int y,
++ int img_width,
+ int img_height,
+ int img_bytes_pre_pixel,
+ int img_rowstride,
+@@ -82,9 +82,9 @@ psplash_fb_text_size (int *width,
+ const char *text);
+
+ void
+-psplash_fb_draw_text (PSplashFB *fb,
+- int x,
+- int y,
++psplash_fb_draw_text (PSplashFB *fb,
++ int x,
++ int y,
+ uint8 red,
+ uint8 green,
+ uint8 blue,
+diff --git a/psplash-write.c b/psplash-write.c
+index a12467a..eee0ea3 100644
+--- a/psplash-write.c
++++ b/psplash-write.c
+@@ -1,5 +1,5 @@
+-/*
+- * pslash - a lightweight framebuffer splashscreen for embedded devices.
++/*
++ * pslash - a lightweight framebuffer splashscreen for embedded devices.
+ *
+ * Copyright (c) 2006 Matthew Allum <mallum@o-hand.com>
+ *
+@@ -19,7 +19,7 @@
+ #include <errno.h>
+ #include "psplash.h"
+
+-int main(int argc, char **argv)
++int main(int argc, char **argv)
+ {
+ char *rundir;
+ int pipe_fd;
+@@ -29,17 +29,17 @@ int main(int argc, char **argv)
+ if (!rundir)
+ rundir = "/run";
+
+- if (argc!=2)
++ if (argc!=2)
+ {
+ fprintf(stderr, "Wrong number of arguments\n");
+ exit(-1);
+ }
+-
++
+ chdir(rundir);
+-
++
+ if ((pipe_fd = open (PSPLASH_FIFO,O_WRONLY|O_NONBLOCK)) == -1)
+ {
+- /* Silently error out instead of covering the boot process in
++ /* Silently error out instead of covering the boot process in
+ errors when psplash has exitted due to a VC switch */
+ /* perror("Error unable to open fifo"); */
+ exit (-1);
+diff --git a/psplash.c b/psplash.c
+index ee1af6b..838ac13 100644
+--- a/psplash.c
++++ b/psplash.c
+@@ -1,9 +1,9 @@
+-/*
+- * pslash - a lightweight framebuffer splashscreen for embedded devices.
++/*
++ * pslash - a lightweight framebuffer splashscreen for embedded devices.
+ *
+ * Copyright (c) 2006 Matthew Allum <mallum@o-hand.com>
+ *
+- * Parts of this file ( fifo handling ) based on 'usplash' copyright
++ * Parts of this file ( fifo handling ) based on 'usplash' copyright
+ * Matthew Garret.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+@@ -46,15 +46,15 @@ psplash_draw_msg (PSplashFB *fb, const char *msg)
+
+ /* Clear */
+
+- psplash_fb_draw_rect (fb,
+- 0,
+- SPLIT_LINE_POS(fb) - h,
++ psplash_fb_draw_rect (fb,
++ 0,
++ SPLIT_LINE_POS(fb) - h,
+ fb->width,
+ h,
+ PSPLASH_BACKGROUND_COLOR);
+
+ psplash_fb_draw_text (fb,
+- (fb->width-w)/2,
++ (fb->width-w)/2,
+ SPLIT_LINE_POS(fb) - h,
+ PSPLASH_TEXT_COLOR,
+ &FONT_DEF,
+@@ -70,13 +70,13 @@ psplash_draw_progress (PSplashFB *fb, int value)
+ /* 4 pix border */
+ x = ((fb->width - BAR_IMG_WIDTH)/2) + 4 ;
+ y = SPLIT_LINE_POS(fb) + 4;
+- width = BAR_IMG_WIDTH - 8;
++ width = BAR_IMG_WIDTH - 8;
+ height = BAR_IMG_HEIGHT - 8;
+
+ if (value > 0)
+ {
+ barwidth = (CLAMP(value,0,100) * width) / 100;
+- psplash_fb_draw_rect (fb, x + barwidth, y,
++ psplash_fb_draw_rect (fb, x + barwidth, y,
+ width - barwidth, height,
+ PSPLASH_BAR_BACKGROUND_COLOR);
+ psplash_fb_draw_rect (fb, x, y, barwidth,
+@@ -85,7 +85,7 @@ psplash_draw_progress (PSplashFB *fb, int value)
+ else
+ {
+ barwidth = (CLAMP(-value,0,100) * width) / 100;
+- psplash_fb_draw_rect (fb, x, y,
++ psplash_fb_draw_rect (fb, x, y,
+ width - barwidth, height,
+ PSPLASH_BAR_BACKGROUND_COLOR);
+ psplash_fb_draw_rect (fb, x + width - barwidth,
+@@ -93,18 +93,18 @@ psplash_draw_progress (PSplashFB *fb, int value)
+ PSPLASH_BAR_COLOR);
+ }
+
+- DBG("value: %i, width: %i, barwidth :%i\n", value,
++ DBG("value: %i, width: %i, barwidth :%i\n", value,
+ width, barwidth);
+ }
+ #endif /* PSPLASH_SHOW_PROGRESS_BAR */
+
+-static int
++static int
+ parse_command (PSplashFB *fb, char *string)
+ {
+ char *command;
+
+ DBG("got cmd %s", string);
+-
++
+ if (strcmp(string,"QUIT") == 0)
+ return 1;
+
+@@ -116,7 +116,7 @@ parse_command (PSplashFB *fb, char *string)
+
+ if (arg)
+ psplash_draw_msg (fb, arg);
+- }
++ }
+ #ifdef PSPLASH_SHOW_PROGRESS_BAR
+ else if (!strcmp(command,"PROGRESS"))
+ {
+@@ -124,9 +124,9 @@ parse_command (PSplashFB *fb, char *string)
+
+ if (arg)
+ psplash_draw_progress (fb, atoi(arg));
+- }
++ }
+ #endif
+- else if (!strcmp(command,"QUIT"))
++ else if (!strcmp(command,"QUIT"))
+ {
+ return 1;
+ }
+@@ -135,8 +135,8 @@ parse_command (PSplashFB *fb, char *string)
+ return 0;
+ }
+
+-void
+-psplash_main (PSplashFB *fb, int pipe_fd, int timeout)
++void
++psplash_main (PSplashFB *fb, int pipe_fd, int timeout)
+ {
+ int err;
+ ssize_t length = 0;
+@@ -154,14 +154,14 @@ psplash_main (PSplashFB *fb, int pipe_fd, int timeout)
+
+ end = command;
+
+- while (1)
++ while (1)
+ {
+- if (timeout != 0)
++ if (timeout != 0)
+ err = select(pipe_fd+1, &descriptors, NULL, NULL, &tv);
+ else
+ err = select(pipe_fd+1, &descriptors, NULL, NULL, NULL);
+-
+- if (err <= 0)
++
++ if (err <= 0)
+ {
+ /*
+ if (errno == EINTR)
+@@ -169,10 +169,10 @@ psplash_main (PSplashFB *fb, int pipe_fd, int timeout)
+ */
+ return;
+ }
+-
++
+ length += read (pipe_fd, end, sizeof(command) - (end - command));
+
+- if (length == 0)
++ if (length == 0)
+ {
+ /* Reopen to see if there's anything more for us */
+ close(pipe_fd);
+@@ -208,10 +208,10 @@ psplash_main (PSplashFB *fb, int pipe_fd, int timeout)
+
+ out:
+ end = &command[length];
+-
++
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+-
++
+ FD_ZERO(&descriptors);
+ FD_SET(pipe_fd,&descriptors);
+ }
+@@ -219,8 +219,8 @@ psplash_main (PSplashFB *fb, int pipe_fd, int timeout)
+ return;
+ }
+
+-int
+-main (int argc, char** argv)
++int
++main (int argc, char** argv)
+ {
+ char *rundir;
+ int pipe_fd, i = 0, angle = 0, fbdev_id = 0, ret = 0;
+@@ -253,8 +253,8 @@ main (int argc, char** argv)
+ }
+
+ fail:
+- fprintf(stderr,
+- "Usage: %s [-n|--no-console-switch][-a|--angle <0|90|180|270>][-f|--fbdev <0..9>]\n",
++ fprintf(stderr,
++ "Usage: %s [-n|--no-console-switch][-a|--angle <0|90|180|270>][-f|--fbdev <0..9>]\n",
+ argv[0]);
+ exit(-1);
+ }
+@@ -268,7 +268,7 @@ main (int argc, char** argv)
+
+ if (mkfifo(PSPLASH_FIFO, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP))
+ {
+- if (errno!=EEXIST)
++ if (errno!=EEXIST)
+ {
+ perror("mkfifo");
+ exit(-1);
+@@ -276,8 +276,8 @@ main (int argc, char** argv)
+ }
+
+ pipe_fd = open (PSPLASH_FIFO,O_RDONLY|O_NONBLOCK);
+-
+- if (pipe_fd==-1)
++
++ if (pipe_fd==-1)
+ {
+ perror("pipe open");
+ exit(-2);
+@@ -301,8 +301,8 @@ main (int argc, char** argv)
+ PSPLASH_BACKGROUND_COLOR);
+
+ /* Draw the Poky logo */
+- psplash_fb_draw_image (fb,
+- (fb->width - POKY_IMG_WIDTH)/2,
++ psplash_fb_draw_image (fb,
++ (fb->width - POKY_IMG_WIDTH)/2,
+ #if PSPLASH_IMG_FULLSCREEN
+ (fb->height - POKY_IMG_HEIGHT)/2,
+ #else
+@@ -317,8 +317,8 @@ main (int argc, char** argv)
+
+ #ifdef PSPLASH_SHOW_PROGRESS_BAR
+ /* Draw progress bar border */
+- psplash_fb_draw_image (fb,
+- (fb->width - BAR_IMG_WIDTH)/2,
++ psplash_fb_draw_image (fb,
++ (fb->width - BAR_IMG_WIDTH)/2,
+ SPLIT_LINE_POS(fb),
+ BAR_IMG_WIDTH,
+ BAR_IMG_HEIGHT,
+diff --git a/psplash.h b/psplash.h
+index 9be44ba..e8b6660 100644
+--- a/psplash.h
++++ b/psplash.h
+@@ -1,5 +1,5 @@
+-/*
+- * pslash - a lightweight framebuffer splashscreen for embedded devices.
++/*
++ * pslash - a lightweight framebuffer splashscreen for embedded devices.
+ *
+ * Copyright (c) 2006 Matthew Allum <mallum@o-hand.com>
+ *
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0003-Fix-unused-result-warnings.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0003-Fix-unused-result-warnings.patch
new file mode 100644
index 00000000..948609d9
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0003-Fix-unused-result-warnings.patch
@@ -0,0 +1,150 @@
+From edb01af9b4789b9c3b908329f6be5819e2cfe954 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:42 +0300
+Subject: [PATCH 03/17] Fix 'unused-result' warnings
+
+This fixes warnings such as:
+
+ ignoring return value of 'chdir', declared with attribute warn_unused_result [-Wunused-result]
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ psplash-systemd.c | 36 +++++++++++++++++++++++++++++++++---
+ psplash-write.c | 23 ++++++++++++++++++-----
+ psplash.c | 5 ++++-
+ 3 files changed, 55 insertions(+), 9 deletions(-)
+
+diff --git a/psplash-systemd.c b/psplash-systemd.c
+index 840bd4e..dcf7e61 100644
+--- a/psplash-systemd.c
++++ b/psplash-systemd.c
+@@ -32,6 +32,7 @@ int get_progress(void)
+ int r;
+ char buffer[20];
+ int len;
++ ssize_t written;
+
+ /* Connect to the system bus */
+ r = sd_bus_new(&bus);
+@@ -71,11 +72,36 @@ int get_progress(void)
+ current_progress = progress;
+
+ len = snprintf(buffer, 20, "PROGRESS %d", (int)(current_progress * 100));
+- write(pipe_fd, buffer, len + 1);
++ written = write(pipe_fd, buffer, len + 1);
++ if (written == -1) {
++ /* EPIPE could mean that psplash detected boot complete sooner
++ then psplash-systemd and exited */
++ if (errno != EPIPE) {
++ perror("write");
++ r = -1;
++ goto finish;
++ }
++ } else if (written < len + 1) {
++ fprintf(stderr, "Wrote %zd bytes, less then expected %d bytes\n",
++ written, len + 1);
++ r = -1;
++ goto finish;
++ }
+
+ if (progress == 1.0) {
+ printf("Systemd reported progress of 1.0, quit psplash.\n");
+- write(pipe_fd, "QUIT", 5);
++ written = write(pipe_fd, "QUIT", 5);
++ if (written == -1) {
++ /* EPIPE could mean that psplash detected boot complete
++ sooner then psplash-systemd and exited */
++ if (errno != EPIPE) {
++ perror("write");
++ r = -1;
++ goto finish;
++ }
++ } else if (written < 5)
++ fprintf(stderr, "Wrote %zd bytes, less then expected 5 bytes\n",
++ written);
+ r = -1;
+ }
+
+@@ -123,7 +149,11 @@ int main()
+ if (!rundir)
+ rundir = "/run";
+
+- chdir(rundir);
++ r = chdir(rundir);
++ if (r < 0) {
++ perror("chdir");
++ goto finish;
++ }
+
+ if ((pipe_fd = open (PSPLASH_FIFO,O_WRONLY|O_NONBLOCK)) == -1) {
+ fprintf(stderr, "Error unable to open fifo");
+diff --git a/psplash-write.c b/psplash-write.c
+index eee0ea3..16b87e1 100644
+--- a/psplash-write.c
++++ b/psplash-write.c
+@@ -21,8 +21,10 @@
+
+ int main(int argc, char **argv)
+ {
+- char *rundir;
+- int pipe_fd;
++ char *rundir;
++ int pipe_fd;
++ size_t count;
++ ssize_t written;
+
+ rundir = getenv("PSPLASH_FIFO_DIR");
+
+@@ -35,7 +37,10 @@ int main(int argc, char **argv)
+ exit(-1);
+ }
+
+- chdir(rundir);
++ if (chdir(rundir)) {
++ perror("chdir");
++ exit(-1);
++ }
+
+ if ((pipe_fd = open (PSPLASH_FIFO,O_WRONLY|O_NONBLOCK)) == -1)
+ {
+@@ -45,8 +50,16 @@ int main(int argc, char **argv)
+ exit (-1);
+ }
+
+- write(pipe_fd, argv[1], strlen(argv[1])+1);
++ count = strlen(argv[1]) + 1;
++ written = write(pipe_fd, argv[1], count);
++ if (written == -1) {
++ perror("write");
++ exit(-1);
++ } else if ((size_t)written < count) {
++ fprintf(stderr, "Wrote %zd bytes, less then expected %zu bytes\n",
++ written, count);
++ exit(-1);
++ }
+
+ return 0;
+ }
+-
+diff --git a/psplash.c b/psplash.c
+index 838ac13..62244ba 100644
+--- a/psplash.c
++++ b/psplash.c
+@@ -264,7 +264,10 @@ main (int argc, char** argv)
+ if (!rundir)
+ rundir = "/run";
+
+- chdir(rundir);
++ if (chdir(rundir)) {
++ perror("chdir");
++ exit(-1);
++ }
+
+ if (mkfifo(PSPLASH_FIFO, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP))
+ {
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0004-Remove-unused-save_termios.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0004-Remove-unused-save_termios.patch
new file mode 100644
index 00000000..7c105ea0
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0004-Remove-unused-save_termios.patch
@@ -0,0 +1,41 @@
+From 733b6d8ae3ed8d5d2972c717bb9a94f65ff6f194 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:43 +0300
+Subject: [PATCH 04/17] Remove unused save_termios
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ psplash-fb.h | 1 -
+ psplash.h | 1 -
+ 2 files changed, 2 deletions(-)
+
+diff --git a/psplash-fb.h b/psplash-fb.h
+index eafa293..6c4599c 100644
+--- a/psplash-fb.h
++++ b/psplash-fb.h
+@@ -22,7 +22,6 @@ typedef struct PSplashFB
+ {
+ int fd;
+ struct fb_var_screeninfo fb_var;
+- struct termios save_termios;
+ int type;
+ int visual;
+ int width, height;
+diff --git a/psplash.h b/psplash.h
+index e8b6660..02d6f32 100644
+--- a/psplash.h
++++ b/psplash.h
+@@ -32,7 +32,6 @@
+ #include <sys/stat.h>
+ #include <sys/time.h>
+ #include <sys/types.h>
+-#include <termios.h>
+ #include <unistd.h>
+ #include <stdbool.h>
+
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0005-Remove-psplash-fb.h-from-psplash.h.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0005-Remove-psplash-fb.h-from-psplash.h.patch
new file mode 100644
index 00000000..602d703e
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0005-Remove-psplash-fb.h-from-psplash.h.patch
@@ -0,0 +1,81 @@
+From 2f1fe1b5233d69cf354ffb5ab182810ef74c7e3d Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:44 +0300
+Subject: [PATCH 05/17] Remove 'psplash-fb.h' from 'psplash.h'
+
+psplash might not be necessary based on framebuffer, it could use DRM
+in future too.
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ psplash-fb.c | 2 +-
+ psplash-fb.h | 3 +++
+ psplash.c | 1 +
+ psplash.h | 2 --
+ 4 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/psplash-fb.c b/psplash-fb.c
+index 1d2d7db..5dea82a 100644
+--- a/psplash-fb.c
++++ b/psplash-fb.c
+@@ -8,7 +8,7 @@
+ */
+
+ #include <endian.h>
+-#include "psplash.h"
++#include "psplash-fb.h"
+
+ static void
+ psplash_wait_for_vsync(PSplashFB *fb)
+diff --git a/psplash-fb.h b/psplash-fb.h
+index 6c4599c..4d5c460 100644
+--- a/psplash-fb.h
++++ b/psplash-fb.h
+@@ -10,6 +10,9 @@
+ #ifndef _HAVE_PSPLASH_FB_H
+ #define _HAVE_PSPLASH_FB_H
+
++#include <linux/fb.h>
++#include "psplash.h"
++
+ enum RGBMode {
+ RGB565,
+ BGR565,
+diff --git a/psplash.c b/psplash.c
+index 62244ba..18c012b 100644
+--- a/psplash.c
++++ b/psplash.c
+@@ -11,6 +11,7 @@
+ */
+
+ #include "psplash.h"
++#include "psplash-fb.h"
+ #include "psplash-config.h"
+ #include "psplash-colors.h"
+ #include "psplash-poky-img.h"
+diff --git a/psplash.h b/psplash.h
+index 02d6f32..ab8e53f 100644
+--- a/psplash.h
++++ b/psplash.h
+@@ -15,7 +15,6 @@
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <limits.h>
+-#include <linux/fb.h>
+ #include <linux/kd.h>
+ #include <linux/vt.h>
+ #include <signal.h>
+@@ -78,7 +77,6 @@ typedef struct PSplashFont
+ PSplashFont;
+
+
+-#include "psplash-fb.h"
+ #include "psplash-console.h"
+
+ #endif
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0006-Extract-plot-pixel-from-psplash-fb.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0006-Extract-plot-pixel-from-psplash-fb.patch
new file mode 100644
index 00000000..5627d5e5
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0006-Extract-plot-pixel-from-psplash-fb.patch
@@ -0,0 +1,624 @@
+From f0504ac0abd16b5e98456fb3ea2777e6b64418ec Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:45 +0300
+Subject: [PATCH 06/17] Extract plot pixel from psplash-fb
+
+psplash_fb_plot_pixel is in fact framebuffer independent.
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ Makefile.am | 3 +-
+ psplash-draw.c | 120 +++++++++++++++++++++++++++++++
+ psplash-draw.h | 51 +++++++++++++
+ psplash-fb.c | 191 +++++++++++--------------------------------------
+ psplash-fb.h | 25 ++-----
+ psplash.c | 20 +++---
+ 6 files changed, 229 insertions(+), 181 deletions(-)
+ create mode 100644 psplash-draw.c
+ create mode 100644 psplash-draw.h
+
+diff --git a/Makefile.am b/Makefile.am
+index 310e126..375b926 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -5,7 +5,8 @@ AM_CFLAGS = $(GCC_FLAGS) $(EXTRA_GCC_FLAGS) -D_GNU_SOURCE -DFONT_HEADER=\"$(FONT
+ psplash_SOURCES = psplash.c psplash.h psplash-fb.c psplash-fb.h \
+ psplash-console.c psplash-console.h \
+ psplash-colors.h psplash-config.h \
+- psplash-poky-img.h psplash-bar-img.h $(FONT_NAME)-font.h
++ psplash-poky-img.h psplash-bar-img.h $(FONT_NAME)-font.h \
++ psplash-draw.c psplash-draw.h
+ BUILT_SOURCES = psplash-poky-img.h psplash-bar-img.h
+
+ psplash_write_SOURCES = psplash-write.c psplash.h
+diff --git a/psplash-draw.c b/psplash-draw.c
+new file mode 100644
+index 0000000..570cfce
+--- /dev/null
++++ b/psplash-draw.c
+@@ -0,0 +1,120 @@
++/*
++ * pslash - a lightweight framebuffer splashscreen for embedded devices.
++ *
++ * Copyright (c) 2006 Matthew Allum <mallum@o-hand.com>
++ *
++ * SPDX-License-Identifier: GPL-2.0-or-later
++ *
++ */
++
++#include "psplash-draw.h"
++
++#define OFFSET(canvas, x, y) (((y) * (canvas)->stride) + ((x) * ((canvas)->bpp >> 3)))
++
++/* TODO: change to 'static inline' as psplash_fb_plot_pixel was before */
++void
++psplash_plot_pixel(PSplashCanvas *canvas,
++ int x,
++ int y,
++ uint8 red,
++ uint8 green,
++ uint8 blue)
++{
++ /* Always write to back data (data) which points to the right data with or
++ * without double buffering support */
++ int off;
++
++ if (x < 0 || x > canvas->width-1 || y < 0 || y > canvas->height-1)
++ return;
++
++ switch (canvas->angle)
++ {
++ case 270:
++ off = OFFSET (canvas, canvas->height - y - 1, x);
++ break;
++ case 180:
++ off = OFFSET (canvas, canvas->width - x - 1, canvas->height - y - 1);
++ break;
++ case 90:
++ off = OFFSET (canvas, y, canvas->width - x - 1);
++ break;
++ case 0:
++ default:
++ off = OFFSET (canvas, x, y);
++ break;
++ }
++
++ if (canvas->rgbmode == RGB565 || canvas->rgbmode == RGB888) {
++ switch (canvas->bpp)
++ {
++ case 24:
++#if __BYTE_ORDER == __BIG_ENDIAN
++ *(canvas->data + off + 0) = red;
++ *(canvas->data + off + 1) = green;
++ *(canvas->data + off + 2) = blue;
++#else
++ *(canvas->data + off + 0) = blue;
++ *(canvas->data + off + 1) = green;
++ *(canvas->data + off + 2) = red;
++#endif
++ break;
++ case 32:
++ *(volatile uint32_t *) (canvas->data + off)
++ = (red << 16) | (green << 8) | (blue);
++ break;
++
++ case 16:
++ *(volatile uint16_t *) (canvas->data + off)
++ = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
++ break;
++ default:
++ /* depth not supported yet */
++ break;
++ }
++ } else if (canvas->rgbmode == BGR565 || canvas->rgbmode == BGR888) {
++ switch (canvas->bpp)
++ {
++ case 24:
++#if __BYTE_ORDER == __BIG_ENDIAN
++ *(canvas->data + off + 0) = blue;
++ *(canvas->data + off + 1) = green;
++ *(canvas->data + off + 2) = red;
++#else
++ *(canvas->data + off + 0) = red;
++ *(canvas->data + off + 1) = green;
++ *(canvas->data + off + 2) = blue;
++#endif
++ break;
++ case 32:
++ *(volatile uint32_t *) (canvas->data + off)
++ = (blue << 16) | (green << 8) | (red);
++ break;
++ case 16:
++ *(volatile uint16_t *) (canvas->data + off)
++ = ((blue >> 3) << 11) | ((green >> 2) << 5) | (red >> 3);
++ break;
++ default:
++ /* depth not supported yet */
++ break;
++ }
++ } else {
++ switch (canvas->bpp)
++ {
++ case 32:
++ *(volatile uint32_t *) (canvas->data + off)
++ = ((red >> (8 - canvas->red_length)) << canvas->red_offset)
++ | ((green >> (8 - canvas->green_length)) << canvas->green_offset)
++ | ((blue >> (8 - canvas->blue_length)) << canvas->blue_offset);
++ break;
++ case 16:
++ *(volatile uint16_t *) (canvas->data + off)
++ = ((red >> (8 - canvas->red_length)) << canvas->red_offset)
++ | ((green >> (8 - canvas->green_length)) << canvas->green_offset)
++ | ((blue >> (8 - canvas->blue_length)) << canvas->blue_offset);
++ break;
++ default:
++ /* depth not supported yet */
++ break;
++ }
++ }
++}
+diff --git a/psplash-draw.h b/psplash-draw.h
+new file mode 100644
+index 0000000..ab2d4d2
+--- /dev/null
++++ b/psplash-draw.h
+@@ -0,0 +1,51 @@
++/*
++ * pslash - a lightweight framebuffer splashscreen for embedded devices.
++ *
++ * Copyright (c) 2006 Matthew Allum <mallum@o-hand.com>
++ *
++ * SPDX-License-Identifier: GPL-2.0-or-later
++ *
++ */
++
++#ifndef _HAVE_PSPLASH_CANVAS_H
++#define _HAVE_PSPLASH_CANVAS_H
++
++#include "psplash.h"
++
++enum RGBMode {
++ RGB565,
++ BGR565,
++ RGB888,
++ BGR888,
++ GENERIC,
++};
++
++typedef struct PSplashCanvas
++{
++ int width, height;
++ int bpp;
++ int stride;
++ char *data;
++
++ int angle;
++
++ enum RGBMode rgbmode;
++ int red_offset;
++ int red_length;
++ int green_offset;
++ int green_length;
++ int blue_offset;
++ int blue_length;
++}
++PSplashCanvas;
++
++/* TODO: Remove after rest of drawing functions migrated to psplash-draw.c */
++void
++psplash_plot_pixel(PSplashCanvas *canvas,
++ int x,
++ int y,
++ uint8 red,
++ uint8 green,
++ uint8 blue);
++
++#endif
+diff --git a/psplash-fb.c b/psplash-fb.c
+index 5dea82a..a7029c5 100644
+--- a/psplash-fb.c
++++ b/psplash-fb.c
+@@ -42,10 +42,11 @@ psplash_fb_flip(PSplashFB *fb, int sync)
+ tmp = fb->fdata;
+ fb->fdata = fb->bdata;
+ fb->bdata = tmp;
++ fb->canvas.data = fb->bdata;
+
+ /* Sync new front to new back when requested */
+ if (sync) {
+- memcpy(fb->bdata, fb->fdata, fb->stride * fb->real_height);
++ memcpy(fb->bdata, fb->fdata, fb->canvas.stride * fb->real_height);
+ }
+ }
+ }
+@@ -220,42 +221,42 @@ psplash_fb_new (int angle, int fbdev_id)
+ }
+ }
+
+- fb->real_width = fb->width = fb_var.xres;
+- fb->real_height = fb->height = fb_var.yres;
+- fb->bpp = fb_var.bits_per_pixel;
+- fb->stride = fb_fix.line_length;
++ fb->real_width = fb->canvas.width = fb_var.xres;
++ fb->real_height = fb->canvas.height = fb_var.yres;
++ fb->canvas.bpp = fb_var.bits_per_pixel;
++ fb->canvas.stride = fb_fix.line_length;
+ fb->type = fb_fix.type;
+ fb->visual = fb_fix.visual;
+
+- fb->red_offset = fb_var.red.offset;
+- fb->red_length = fb_var.red.length;
+- fb->green_offset = fb_var.green.offset;
+- fb->green_length = fb_var.green.length;
+- fb->blue_offset = fb_var.blue.offset;
+- fb->blue_length = fb_var.blue.length;
+-
+- if (fb->red_offset == 11 && fb->red_length == 5 &&
+- fb->green_offset == 5 && fb->green_length == 6 &&
+- fb->blue_offset == 0 && fb->blue_length == 5) {
+- fb->rgbmode = RGB565;
+- } else if (fb->red_offset == 0 && fb->red_length == 5 &&
+- fb->green_offset == 5 && fb->green_length == 6 &&
+- fb->blue_offset == 11 && fb->blue_length == 5) {
+- fb->rgbmode = BGR565;
+- } else if (fb->red_offset == 16 && fb->red_length == 8 &&
+- fb->green_offset == 8 && fb->green_length == 8 &&
+- fb->blue_offset == 0 && fb->blue_length == 8) {
+- fb->rgbmode = RGB888;
+- } else if (fb->red_offset == 0 && fb->red_length == 8 &&
+- fb->green_offset == 8 && fb->green_length == 8 &&
+- fb->blue_offset == 16 && fb->blue_length == 8) {
+- fb->rgbmode = BGR888;
++ fb->canvas.red_offset = fb_var.red.offset;
++ fb->canvas.red_length = fb_var.red.length;
++ fb->canvas.green_offset = fb_var.green.offset;
++ fb->canvas.green_length = fb_var.green.length;
++ fb->canvas.blue_offset = fb_var.blue.offset;
++ fb->canvas.blue_length = fb_var.blue.length;
++
++ if (fb->canvas.red_offset == 11 && fb->canvas.red_length == 5 &&
++ fb->canvas.green_offset == 5 && fb->canvas.green_length == 6 &&
++ fb->canvas.blue_offset == 0 && fb->canvas.blue_length == 5) {
++ fb->canvas.rgbmode = RGB565;
++ } else if (fb->canvas.red_offset == 0 && fb->canvas.red_length == 5 &&
++ fb->canvas.green_offset == 5 && fb->canvas.green_length == 6 &&
++ fb->canvas.blue_offset == 11 && fb->canvas.blue_length == 5) {
++ fb->canvas.rgbmode = BGR565;
++ } else if (fb->canvas.red_offset == 16 && fb->canvas.red_length == 8 &&
++ fb->canvas.green_offset == 8 && fb->canvas.green_length == 8 &&
++ fb->canvas.blue_offset == 0 && fb->canvas.blue_length == 8) {
++ fb->canvas.rgbmode = RGB888;
++ } else if (fb->canvas.red_offset == 0 && fb->canvas.red_length == 8 &&
++ fb->canvas.green_offset == 8 && fb->canvas.green_length == 8 &&
++ fb->canvas.blue_offset == 16 && fb->canvas.blue_length == 8) {
++ fb->canvas.rgbmode = BGR888;
+ } else {
+- fb->rgbmode = GENERIC;
++ fb->canvas.rgbmode = GENERIC;
+ }
+
+ DBG("width: %i, height: %i, bpp: %i, stride: %i",
+- fb->width, fb->height, fb->bpp, fb->stride);
++ fb->canvas.width, fb->canvas.height, fb->canvas.bpp, fb->canvas.stride);
+
+ fb->base = (char *) mmap ((caddr_t) NULL,
+ fb_fix.smem_len,
+@@ -279,16 +280,17 @@ psplash_fb_new (int angle, int fbdev_id)
+ if (fb->fb_var.yoffset == 0) {
+ printf("to back\n");
+ fb->fdata = fb->data;
+- fb->bdata = fb->data + fb->stride * fb->height;
++ fb->bdata = fb->data + fb->canvas.stride * fb->canvas.height;
+ } else {
+ printf("to front\n");
+- fb->fdata = fb->data + fb->stride * fb->height;
++ fb->fdata = fb->data + fb->canvas.stride * fb->canvas.height;
+ fb->bdata = fb->data;
+ }
+ } else {
+ fb->fdata = fb->data;
+ fb->bdata = fb->data;
+ }
++ fb->canvas.data = fb->bdata;
+
+ #if 0
+ /* FIXME: No support for 8pp as yet */
+@@ -312,14 +314,14 @@ psplash_fb_new (int angle, int fbdev_id)
+ status = 2;
+ #endif
+
+- fb->angle = angle;
++ fb->canvas.angle = angle;
+
+- switch (fb->angle)
++ switch (angle)
+ {
+ case 270:
+ case 90:
+- fb->width = fb->real_height;
+- fb->height = fb->real_width;
++ fb->canvas.width = fb->real_height;
++ fb->canvas.height = fb->real_width;
+ break;
+ case 180:
+ case 0:
+@@ -337,115 +339,6 @@ psplash_fb_new (int angle, int fbdev_id)
+ return NULL;
+ }
+
+-#define OFFSET(fb,x,y) (((y) * (fb)->stride) + ((x) * ((fb)->bpp >> 3)))
+-
+-static inline void
+-psplash_fb_plot_pixel (PSplashFB *fb,
+- int x,
+- int y,
+- uint8 red,
+- uint8 green,
+- uint8 blue)
+-{
+- /* Always write to back data (bdata) which points to the right data with or
+- * without double buffering support */
+- int off;
+-
+- if (x < 0 || x > fb->width-1 || y < 0 || y > fb->height-1)
+- return;
+-
+- switch (fb->angle)
+- {
+- case 270:
+- off = OFFSET (fb, fb->height - y - 1, x);
+- break;
+- case 180:
+- off = OFFSET (fb, fb->width - x - 1, fb->height - y - 1);
+- break;
+- case 90:
+- off = OFFSET (fb, y, fb->width - x - 1);
+- break;
+- case 0:
+- default:
+- off = OFFSET (fb, x, y);
+- break;
+- }
+-
+- if (fb->rgbmode == RGB565 || fb->rgbmode == RGB888) {
+- switch (fb->bpp)
+- {
+- case 24:
+-#if __BYTE_ORDER == __BIG_ENDIAN
+- *(fb->bdata + off + 0) = red;
+- *(fb->bdata + off + 1) = green;
+- *(fb->bdata + off + 2) = blue;
+-#else
+- *(fb->bdata + off + 0) = blue;
+- *(fb->bdata + off + 1) = green;
+- *(fb->bdata + off + 2) = red;
+-#endif
+- break;
+- case 32:
+- *(volatile uint32_t *) (fb->bdata + off)
+- = (red << 16) | (green << 8) | (blue);
+- break;
+-
+- case 16:
+- *(volatile uint16_t *) (fb->bdata + off)
+- = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
+- break;
+- default:
+- /* depth not supported yet */
+- break;
+- }
+- } else if (fb->rgbmode == BGR565 || fb->rgbmode == BGR888) {
+- switch (fb->bpp)
+- {
+- case 24:
+-#if __BYTE_ORDER == __BIG_ENDIAN
+- *(fb->bdata + off + 0) = blue;
+- *(fb->bdata + off + 1) = green;
+- *(fb->bdata + off + 2) = red;
+-#else
+- *(fb->bdata + off + 0) = red;
+- *(fb->bdata + off + 1) = green;
+- *(fb->bdata + off + 2) = blue;
+-#endif
+- break;
+- case 32:
+- *(volatile uint32_t *) (fb->bdata + off)
+- = (blue << 16) | (green << 8) | (red);
+- break;
+- case 16:
+- *(volatile uint16_t *) (fb->bdata + off)
+- = ((blue >> 3) << 11) | ((green >> 2) << 5) | (red >> 3);
+- break;
+- default:
+- /* depth not supported yet */
+- break;
+- }
+- } else {
+- switch (fb->bpp)
+- {
+- case 32:
+- *(volatile uint32_t *) (fb->bdata + off)
+- = ((red >> (8 - fb->red_length)) << fb->red_offset)
+- | ((green >> (8 - fb->green_length)) << fb->green_offset)
+- | ((blue >> (8 - fb->blue_length)) << fb->blue_offset);
+- break;
+- case 16:
+- *(volatile uint16_t *) (fb->bdata + off)
+- = ((red >> (8 - fb->red_length)) << fb->red_offset)
+- | ((green >> (8 - fb->green_length)) << fb->green_offset)
+- | ((blue >> (8 - fb->blue_length)) << fb->blue_offset);
+- break;
+- default:
+- /* depth not supported yet */
+- break;
+- }
+- }
+-}
+-
+ void
+ psplash_fb_draw_rect (PSplashFB *fb,
+ int x,
+@@ -460,7 +353,7 @@ psplash_fb_draw_rect (PSplashFB *fb,
+
+ for (dy=0; dy < height; dy++)
+ for (dx=0; dx < width; dx++)
+- psplash_fb_plot_pixel (fb, x+dx, y+dy, red, green, blue);
++ psplash_plot_pixel(&fb->canvas, x+dx, y+dy, red, green, blue);
+ }
+
+ void
+@@ -493,7 +386,7 @@ psplash_fb_draw_image (PSplashFB *fb,
+ do
+ {
+ if ((img_bytes_per_pixel < 4 || *(p+3)) && dx < img_width)
+- psplash_fb_plot_pixel (fb, x+dx, y+dy, *(p), *(p+1), *(p+2));
++ psplash_plot_pixel(&fb->canvas, x+dx, y+dy, *(p), *(p+1), *(p+2));
+ if (++dx * img_bytes_per_pixel >= img_rowstride) { dx=0; dy++; }
+ }
+ while (--len);
+@@ -507,7 +400,7 @@ psplash_fb_draw_image (PSplashFB *fb,
+ do
+ {
+ if ((img_bytes_per_pixel < 4 || *(p+3)) && dx < img_width)
+- psplash_fb_plot_pixel (fb, x+dx, y+dy, *(p), *(p+1), *(p+2));
++ psplash_plot_pixel(&fb->canvas, x+dx, y+dy, *(p), *(p+1), *(p+2));
+ if (++dx * img_bytes_per_pixel >= img_rowstride) { dx=0; dy++; }
+ p += img_bytes_per_pixel;
+ }
+@@ -613,7 +506,7 @@ psplash_fb_draw_text (PSplashFB *fb,
+ for (cx = 0; cx < w; cx++)
+ {
+ if (g & 0x80000000)
+- psplash_fb_plot_pixel (fb, x+dx+cx, y+dy+cy,
++ psplash_plot_pixel(&fb->canvas, x+dx+cx, y+dy+cy,
+ red, green, blue);
+ g <<= 1;
+ }
+diff --git a/psplash-fb.h b/psplash-fb.h
+index 4d5c460..eb02c62 100644
+--- a/psplash-fb.h
++++ b/psplash-fb.h
+@@ -11,25 +11,16 @@
+ #define _HAVE_PSPLASH_FB_H
+
+ #include <linux/fb.h>
+-#include "psplash.h"
+-
+-enum RGBMode {
+- RGB565,
+- BGR565,
+- RGB888,
+- BGR888,
+- GENERIC,
+-};
++#include "psplash-draw.h"
+
+ typedef struct PSplashFB
+ {
++ PSplashCanvas canvas;
++
+ int fd;
+ struct fb_var_screeninfo fb_var;
+ int type;
+ int visual;
+- int width, height;
+- int bpp;
+- int stride;
+ char *data;
+ char *base;
+
+@@ -38,16 +29,8 @@ typedef struct PSplashFB
+ char *bdata;
+ char *fdata;
+
+- int angle, fbdev_id;
++ int fbdev_id;
+ int real_width, real_height;
+-
+- enum RGBMode rgbmode;
+- int red_offset;
+- int red_length;
+- int green_offset;
+- int green_length;
+- int blue_offset;
+- int blue_length;
+ }
+ PSplashFB;
+
+diff --git a/psplash.c b/psplash.c
+index 18c012b..f23f03d 100644
+--- a/psplash.c
++++ b/psplash.c
+@@ -22,10 +22,10 @@
+ #include FONT_HEADER
+
+ #define SPLIT_LINE_POS(fb) \
+- ( (fb)->height \
++ ( (fb)->canvas.height \
+ - (( PSPLASH_IMG_SPLIT_DENOMINATOR \
+ - PSPLASH_IMG_SPLIT_NUMERATOR) \
+- * (fb)->height / PSPLASH_IMG_SPLIT_DENOMINATOR) \
++ * (fb)->canvas.height / PSPLASH_IMG_SPLIT_DENOMINATOR) \
+ )
+
+ void
+@@ -50,12 +50,12 @@ psplash_draw_msg (PSplashFB *fb, const char *msg)
+ psplash_fb_draw_rect (fb,
+ 0,
+ SPLIT_LINE_POS(fb) - h,
+- fb->width,
++ fb->canvas.width,
+ h,
+ PSPLASH_BACKGROUND_COLOR);
+
+ psplash_fb_draw_text (fb,
+- (fb->width-w)/2,
++ (fb->canvas.width-w)/2,
+ SPLIT_LINE_POS(fb) - h,
+ PSPLASH_TEXT_COLOR,
+ &FONT_DEF,
+@@ -69,7 +69,7 @@ psplash_draw_progress (PSplashFB *fb, int value)
+ int x, y, width, height, barwidth;
+
+ /* 4 pix border */
+- x = ((fb->width - BAR_IMG_WIDTH)/2) + 4 ;
++ x = ((fb->canvas.width - BAR_IMG_WIDTH)/2) + 4 ;
+ y = SPLIT_LINE_POS(fb) + 4;
+ width = BAR_IMG_WIDTH - 8;
+ height = BAR_IMG_HEIGHT - 8;
+@@ -301,16 +301,16 @@ main (int argc, char** argv)
+ #endif
+
+ /* Clear the background with #ecece1 */
+- psplash_fb_draw_rect (fb, 0, 0, fb->width, fb->height,
++ psplash_fb_draw_rect (fb, 0, 0, fb->canvas.width, fb->canvas.height,
+ PSPLASH_BACKGROUND_COLOR);
+
+ /* Draw the Poky logo */
+ psplash_fb_draw_image (fb,
+- (fb->width - POKY_IMG_WIDTH)/2,
++ (fb->canvas.width - POKY_IMG_WIDTH)/2,
+ #if PSPLASH_IMG_FULLSCREEN
+- (fb->height - POKY_IMG_HEIGHT)/2,
++ (fb->canvas.height - POKY_IMG_HEIGHT)/2,
+ #else
+- (fb->height * PSPLASH_IMG_SPLIT_NUMERATOR
++ (fb->canvas.height * PSPLASH_IMG_SPLIT_NUMERATOR
+ / PSPLASH_IMG_SPLIT_DENOMINATOR - POKY_IMG_HEIGHT)/2,
+ #endif
+ POKY_IMG_WIDTH,
+@@ -322,7 +322,7 @@ main (int argc, char** argv)
+ #ifdef PSPLASH_SHOW_PROGRESS_BAR
+ /* Draw progress bar border */
+ psplash_fb_draw_image (fb,
+- (fb->width - BAR_IMG_WIDTH)/2,
++ (fb->canvas.width - BAR_IMG_WIDTH)/2,
+ SPLIT_LINE_POS(fb),
+ BAR_IMG_WIDTH,
+ BAR_IMG_HEIGHT,
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0007-Extract-draw-rect-image-from-psplash-fb.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0007-Extract-draw-rect-image-from-psplash-fb.patch
new file mode 100644
index 00000000..2e897d4c
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0007-Extract-draw-rect-image-from-psplash-fb.patch
@@ -0,0 +1,299 @@
+From d0f899114600ee25eb2d7d2c089deb549c371bd2 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:46 +0300
+Subject: [PATCH 07/17] Extract draw rect/image from psplash-fb
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ psplash-draw.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ psplash-draw.h | 20 +++++++++++++++
+ psplash-fb.c | 70 --------------------------------------------------
+ psplash-fb.h | 20 ---------------
+ psplash.c | 16 ++++++------
+ 5 files changed, 98 insertions(+), 98 deletions(-)
+
+diff --git a/psplash-draw.c b/psplash-draw.c
+index 570cfce..6887e22 100644
+--- a/psplash-draw.c
++++ b/psplash-draw.c
+@@ -118,3 +118,73 @@ psplash_plot_pixel(PSplashCanvas *canvas,
+ }
+ }
+ }
++
++void
++psplash_draw_rect(PSplashCanvas *canvas,
++ int x,
++ int y,
++ int width,
++ int height,
++ uint8 red,
++ uint8 green,
++ uint8 blue)
++{
++ int dx, dy;
++
++ for (dy=0; dy < height; dy++)
++ for (dx=0; dx < width; dx++)
++ psplash_plot_pixel(canvas, x+dx, y+dy, red, green, blue);
++}
++
++void
++psplash_draw_image(PSplashCanvas *canvas,
++ int x,
++ int y,
++ int img_width,
++ int img_height,
++ int img_bytes_per_pixel,
++ int img_rowstride,
++ uint8 *rle_data)
++{
++ uint8 *p = rle_data;
++ int dx = 0, dy = 0, total_len;
++ unsigned int len;
++
++ total_len = img_rowstride * img_height;
++
++ /* FIXME: Optimise, check for over runs ... */
++ while ((p - rle_data) < total_len)
++ {
++ len = *(p++);
++
++ if (len & 128)
++ {
++ len -= 128;
++
++ if (len == 0) break;
++
++ do
++ {
++ if ((img_bytes_per_pixel < 4 || *(p+3)) && dx < img_width)
++ psplash_plot_pixel(canvas, x+dx, y+dy, *(p), *(p+1), *(p+2));
++ if (++dx * img_bytes_per_pixel >= img_rowstride) { dx=0; dy++; }
++ }
++ while (--len);
++
++ p += img_bytes_per_pixel;
++ }
++ else
++ {
++ if (len == 0) break;
++
++ do
++ {
++ if ((img_bytes_per_pixel < 4 || *(p+3)) && dx < img_width)
++ psplash_plot_pixel(canvas, x+dx, y+dy, *(p), *(p+1), *(p+2));
++ if (++dx * img_bytes_per_pixel >= img_rowstride) { dx=0; dy++; }
++ p += img_bytes_per_pixel;
++ }
++ while (--len && (p - rle_data) < total_len);
++ }
++ }
++}
+diff --git a/psplash-draw.h b/psplash-draw.h
+index ab2d4d2..f8361da 100644
+--- a/psplash-draw.h
++++ b/psplash-draw.h
+@@ -48,4 +48,24 @@ psplash_plot_pixel(PSplashCanvas *canvas,
+ uint8 green,
+ uint8 blue);
+
++void
++psplash_draw_rect(PSplashCanvas *canvas,
++ int x,
++ int y,
++ int width,
++ int height,
++ uint8 red,
++ uint8 green,
++ uint8 blue);
++
++void
++psplash_draw_image(PSplashCanvas *canvas,
++ int x,
++ int y,
++ int img_width,
++ int img_height,
++ int img_bytes_per_pixel,
++ int img_rowstride,
++ uint8 *rle_data);
++
+ #endif
+diff --git a/psplash-fb.c b/psplash-fb.c
+index a7029c5..07839d5 100644
+--- a/psplash-fb.c
++++ b/psplash-fb.c
+@@ -339,76 +339,6 @@ psplash_fb_new (int angle, int fbdev_id)
+ return NULL;
+ }
+
+-void
+-psplash_fb_draw_rect (PSplashFB *fb,
+- int x,
+- int y,
+- int width,
+- int height,
+- uint8 red,
+- uint8 green,
+- uint8 blue)
+-{
+- int dx, dy;
+-
+- for (dy=0; dy < height; dy++)
+- for (dx=0; dx < width; dx++)
+- psplash_plot_pixel(&fb->canvas, x+dx, y+dy, red, green, blue);
+-}
+-
+-void
+-psplash_fb_draw_image (PSplashFB *fb,
+- int x,
+- int y,
+- int img_width,
+- int img_height,
+- int img_bytes_per_pixel,
+- int img_rowstride,
+- uint8 *rle_data)
+-{
+- uint8 *p = rle_data;
+- int dx = 0, dy = 0, total_len;
+- unsigned int len;
+-
+- total_len = img_rowstride * img_height;
+-
+- /* FIXME: Optimise, check for over runs ... */
+- while ((p - rle_data) < total_len)
+- {
+- len = *(p++);
+-
+- if (len & 128)
+- {
+- len -= 128;
+-
+- if (len == 0) break;
+-
+- do
+- {
+- if ((img_bytes_per_pixel < 4 || *(p+3)) && dx < img_width)
+- psplash_plot_pixel(&fb->canvas, x+dx, y+dy, *(p), *(p+1), *(p+2));
+- if (++dx * img_bytes_per_pixel >= img_rowstride) { dx=0; dy++; }
+- }
+- while (--len);
+-
+- p += img_bytes_per_pixel;
+- }
+- else
+- {
+- if (len == 0) break;
+-
+- do
+- {
+- if ((img_bytes_per_pixel < 4 || *(p+3)) && dx < img_width)
+- psplash_plot_pixel(&fb->canvas, x+dx, y+dy, *(p), *(p+1), *(p+2));
+- if (++dx * img_bytes_per_pixel >= img_rowstride) { dx=0; dy++; }
+- p += img_bytes_per_pixel;
+- }
+- while (--len && (p - rle_data) < total_len);
+- }
+- }
+-}
+-
+ /* Font rendering code based on BOGL by Ben Pfaff */
+
+ static int
+diff --git a/psplash-fb.h b/psplash-fb.h
+index eb02c62..1eecb47 100644
+--- a/psplash-fb.h
++++ b/psplash-fb.h
+@@ -40,26 +40,6 @@ psplash_fb_destroy (PSplashFB *fb);
+ PSplashFB*
+ psplash_fb_new (int angle, int fbdev_id);
+
+-void
+-psplash_fb_draw_rect (PSplashFB *fb,
+- int x,
+- int y,
+- int width,
+- int height,
+- uint8 red,
+- uint8 green,
+- uint8 blue);
+-
+-void
+-psplash_fb_draw_image (PSplashFB *fb,
+- int x,
+- int y,
+- int img_width,
+- int img_height,
+- int img_bytes_pre_pixel,
+- int img_rowstride,
+- uint8 *rle_data);
+-
+ void
+ psplash_fb_text_size (int *width,
+ int *height,
+diff --git a/psplash.c b/psplash.c
+index f23f03d..2aeb583 100644
+--- a/psplash.c
++++ b/psplash.c
+@@ -47,7 +47,7 @@ psplash_draw_msg (PSplashFB *fb, const char *msg)
+
+ /* Clear */
+
+- psplash_fb_draw_rect (fb,
++ psplash_draw_rect(&fb->canvas,
+ 0,
+ SPLIT_LINE_POS(fb) - h,
+ fb->canvas.width,
+@@ -77,19 +77,19 @@ psplash_draw_progress (PSplashFB *fb, int value)
+ if (value > 0)
+ {
+ barwidth = (CLAMP(value,0,100) * width) / 100;
+- psplash_fb_draw_rect (fb, x + barwidth, y,
++ psplash_draw_rect(&fb->canvas, x + barwidth, y,
+ width - barwidth, height,
+ PSPLASH_BAR_BACKGROUND_COLOR);
+- psplash_fb_draw_rect (fb, x, y, barwidth,
++ psplash_draw_rect(&fb->canvas, x, y, barwidth,
+ height, PSPLASH_BAR_COLOR);
+ }
+ else
+ {
+ barwidth = (CLAMP(-value,0,100) * width) / 100;
+- psplash_fb_draw_rect (fb, x, y,
++ psplash_draw_rect(&fb->canvas, x, y,
+ width - barwidth, height,
+ PSPLASH_BAR_BACKGROUND_COLOR);
+- psplash_fb_draw_rect (fb, x + width - barwidth,
++ psplash_draw_rect(&fb->canvas, x + width - barwidth,
+ y, barwidth, height,
+ PSPLASH_BAR_COLOR);
+ }
+@@ -301,11 +301,11 @@ main (int argc, char** argv)
+ #endif
+
+ /* Clear the background with #ecece1 */
+- psplash_fb_draw_rect (fb, 0, 0, fb->canvas.width, fb->canvas.height,
++ psplash_draw_rect(&fb->canvas, 0, 0, fb->canvas.width, fb->canvas.height,
+ PSPLASH_BACKGROUND_COLOR);
+
+ /* Draw the Poky logo */
+- psplash_fb_draw_image (fb,
++ psplash_draw_image(&fb->canvas,
+ (fb->canvas.width - POKY_IMG_WIDTH)/2,
+ #if PSPLASH_IMG_FULLSCREEN
+ (fb->canvas.height - POKY_IMG_HEIGHT)/2,
+@@ -321,7 +321,7 @@ main (int argc, char** argv)
+
+ #ifdef PSPLASH_SHOW_PROGRESS_BAR
+ /* Draw progress bar border */
+- psplash_fb_draw_image (fb,
++ psplash_draw_image(&fb->canvas,
+ (fb->canvas.width - BAR_IMG_WIDTH)/2,
+ SPLIT_LINE_POS(fb),
+ BAR_IMG_WIDTH,
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0008-Extract-draw-font-from-psplash-fb.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0008-Extract-draw-font-from-psplash-fb.patch
new file mode 100644
index 00000000..a62e939c
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0008-Extract-draw-font-from-psplash-fb.patch
@@ -0,0 +1,350 @@
+From 532e889486ed4c6b254893e89c63cc4395cc83da Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:47 +0300
+Subject: [PATCH 08/17] Extract draw font from psplash-fb
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ psplash-draw.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ psplash-draw.h | 25 ++++++++----
+ psplash-fb.c | 108 ------------------------------------------------
+ psplash-fb.h | 16 --------
+ psplash.c | 4 +-
+ 5 files changed, 125 insertions(+), 137 deletions(-)
+
+diff --git a/psplash-draw.c b/psplash-draw.c
+index 6887e22..aa9887a 100644
+--- a/psplash-draw.c
++++ b/psplash-draw.c
+@@ -11,8 +11,7 @@
+
+ #define OFFSET(canvas, x, y) (((y) * (canvas)->stride) + ((x) * ((canvas)->bpp >> 3)))
+
+-/* TODO: change to 'static inline' as psplash_fb_plot_pixel was before */
+-void
++static inline void
+ psplash_plot_pixel(PSplashCanvas *canvas,
+ int x,
+ int y,
+@@ -188,3 +187,109 @@ psplash_draw_image(PSplashCanvas *canvas,
+ }
+ }
+ }
++
++/* Font rendering code based on BOGL by Ben Pfaff */
++
++static int
++psplash_font_glyph (const PSplashFont *font, wchar_t wc, u_int32_t **bitmap)
++{
++ int mask = font->index_mask;
++ int i;
++
++ for (;;)
++ {
++ for (i = font->offset[wc & mask]; font->index[i]; i += 2)
++ {
++ if ((wchar_t)(font->index[i] & ~mask) == (wc & ~mask))
++ {
++ if (bitmap != NULL)
++ *bitmap = &font->content[font->index[i+1]];
++ return font->index[i] & mask;
++ }
++ }
++ }
++ return 0;
++}
++
++void
++psplash_text_size(int *width,
++ int *height,
++ const PSplashFont *font,
++ const char *text)
++{
++ char *c = (char*)text;
++ wchar_t wc;
++ int k, n, w, h, mw;
++
++ n = strlen (text);
++ mw = h = w = 0;
++
++ mbtowc (0, 0, 0);
++ for (; (k = mbtowc (&wc, c, n)) > 0; c += k, n -= k)
++ {
++ if (*c == '\n')
++ {
++ if (w > mw)
++ mw = w;
++ w = 0;
++ h += font->height;
++ continue;
++ }
++
++ w += psplash_font_glyph (font, wc, NULL);
++ }
++
++ *width = (w > mw) ? w : mw;
++ *height = (h == 0) ? font->height : h;
++}
++
++void
++psplash_draw_text(PSplashCanvas *canvas,
++ int x,
++ int y,
++ uint8 red,
++ uint8 green,
++ uint8 blue,
++ const PSplashFont *font,
++ const char *text)
++{
++ int h, w, k, n, cx, cy, dx, dy;
++ char *c = (char*)text;
++ wchar_t wc;
++
++ n = strlen (text);
++ h = font->height;
++ dx = dy = 0;
++
++ mbtowc (0, 0, 0);
++ for (; (k = mbtowc (&wc, c, n)) > 0; c += k, n -= k)
++ {
++ u_int32_t *glyph = NULL;
++
++ if (*c == '\n')
++ {
++ dy += h;
++ dx = 0;
++ continue;
++ }
++
++ w = psplash_font_glyph (font, wc, &glyph);
++
++ if (glyph == NULL)
++ continue;
++
++ for (cy = 0; cy < h; cy++)
++ {
++ u_int32_t g = *glyph++;
++
++ for (cx = 0; cx < w; cx++)
++ {
++ if (g & 0x80000000)
++ psplash_plot_pixel(canvas, x+dx+cx, y+dy+cy, red, green, blue);
++ g <<= 1;
++ }
++ }
++
++ dx += w;
++ }
++}
+diff --git a/psplash-draw.h b/psplash-draw.h
+index f8361da..44546b0 100644
+--- a/psplash-draw.h
++++ b/psplash-draw.h
+@@ -39,15 +39,6 @@ typedef struct PSplashCanvas
+ }
+ PSplashCanvas;
+
+-/* TODO: Remove after rest of drawing functions migrated to psplash-draw.c */
+-void
+-psplash_plot_pixel(PSplashCanvas *canvas,
+- int x,
+- int y,
+- uint8 red,
+- uint8 green,
+- uint8 blue);
+-
+ void
+ psplash_draw_rect(PSplashCanvas *canvas,
+ int x,
+@@ -68,4 +59,20 @@ psplash_draw_image(PSplashCanvas *canvas,
+ int img_rowstride,
+ uint8 *rle_data);
+
++void
++psplash_text_size(int *width,
++ int *height,
++ const PSplashFont *font,
++ const char *text);
++
++void
++psplash_draw_text(PSplashCanvas *canvas,
++ int x,
++ int y,
++ uint8 red,
++ uint8 green,
++ uint8 blue,
++ const PSplashFont *font,
++ const char *text);
++
+ #endif
+diff --git a/psplash-fb.c b/psplash-fb.c
+index 07839d5..dd50a5a 100644
+--- a/psplash-fb.c
++++ b/psplash-fb.c
+@@ -338,111 +338,3 @@ psplash_fb_new (int angle, int fbdev_id)
+
+ return NULL;
+ }
+-
+-/* Font rendering code based on BOGL by Ben Pfaff */
+-
+-static int
+-psplash_font_glyph (const PSplashFont *font, wchar_t wc, u_int32_t **bitmap)
+-{
+- int mask = font->index_mask;
+- int i;
+-
+- for (;;)
+- {
+- for (i = font->offset[wc & mask]; font->index[i]; i += 2)
+- {
+- if ((wchar_t)(font->index[i] & ~mask) == (wc & ~mask))
+- {
+- if (bitmap != NULL)
+- *bitmap = &font->content[font->index[i+1]];
+- return font->index[i] & mask;
+- }
+- }
+- }
+- return 0;
+-}
+-
+-void
+-psplash_fb_text_size (int *width,
+- int *height,
+- const PSplashFont *font,
+- const char *text)
+-{
+- char *c = (char*)text;
+- wchar_t wc;
+- int k, n, w, h, mw;
+-
+- n = strlen (text);
+- mw = h = w = 0;
+-
+- mbtowc (0, 0, 0);
+- for (; (k = mbtowc (&wc, c, n)) > 0; c += k, n -= k)
+- {
+- if (*c == '\n')
+- {
+- if (w > mw)
+- mw = w;
+- w = 0;
+- h += font->height;
+- continue;
+- }
+-
+- w += psplash_font_glyph (font, wc, NULL);
+- }
+-
+- *width = (w > mw) ? w : mw;
+- *height = (h == 0) ? font->height : h;
+-}
+-
+-void
+-psplash_fb_draw_text (PSplashFB *fb,
+- int x,
+- int y,
+- uint8 red,
+- uint8 green,
+- uint8 blue,
+- const PSplashFont *font,
+- const char *text)
+-{
+- int h, w, k, n, cx, cy, dx, dy;
+- char *c = (char*)text;
+- wchar_t wc;
+-
+- n = strlen (text);
+- h = font->height;
+- dx = dy = 0;
+-
+- mbtowc (0, 0, 0);
+- for (; (k = mbtowc (&wc, c, n)) > 0; c += k, n -= k)
+- {
+- u_int32_t *glyph = NULL;
+-
+- if (*c == '\n')
+- {
+- dy += h;
+- dx = 0;
+- continue;
+- }
+-
+- w = psplash_font_glyph (font, wc, &glyph);
+-
+- if (glyph == NULL)
+- continue;
+-
+- for (cy = 0; cy < h; cy++)
+- {
+- u_int32_t g = *glyph++;
+-
+- for (cx = 0; cx < w; cx++)
+- {
+- if (g & 0x80000000)
+- psplash_plot_pixel(&fb->canvas, x+dx+cx, y+dy+cy,
+- red, green, blue);
+- g <<= 1;
+- }
+- }
+-
+- dx += w;
+- }
+-}
+-
+diff --git a/psplash-fb.h b/psplash-fb.h
+index 1eecb47..1b16bd5 100644
+--- a/psplash-fb.h
++++ b/psplash-fb.h
+@@ -40,22 +40,6 @@ psplash_fb_destroy (PSplashFB *fb);
+ PSplashFB*
+ psplash_fb_new (int angle, int fbdev_id);
+
+-void
+-psplash_fb_text_size (int *width,
+- int *height,
+- const PSplashFont *font,
+- const char *text);
+-
+-void
+-psplash_fb_draw_text (PSplashFB *fb,
+- int x,
+- int y,
+- uint8 red,
+- uint8 green,
+- uint8 blue,
+- const PSplashFont *font,
+- const char *text);
+-
+ void
+ psplash_fb_flip(PSplashFB *fb, int sync);
+
+diff --git a/psplash.c b/psplash.c
+index 2aeb583..1a5e543 100644
+--- a/psplash.c
++++ b/psplash.c
+@@ -41,7 +41,7 @@ psplash_draw_msg (PSplashFB *fb, const char *msg)
+ {
+ int w, h;
+
+- psplash_fb_text_size (&w, &h, &FONT_DEF, msg);
++ psplash_text_size(&w, &h, &FONT_DEF, msg);
+
+ DBG("displaying '%s' %ix%i\n", msg, w, h);
+
+@@ -54,7 +54,7 @@ psplash_draw_msg (PSplashFB *fb, const char *msg)
+ h,
+ PSPLASH_BACKGROUND_COLOR);
+
+- psplash_fb_draw_text (fb,
++ psplash_draw_text(&fb->canvas,
+ (fb->canvas.width-w)/2,
+ SPLIT_LINE_POS(fb) - h,
+ PSPLASH_TEXT_COLOR,
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0009-psplash.c-Make-psplash_draw_-msg-progress-independen.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0009-psplash.c-Make-psplash_draw_-msg-progress-independen.patch
new file mode 100644
index 00000000..9cd2692c
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0009-psplash.c-Make-psplash_draw_-msg-progress-independen.patch
@@ -0,0 +1,191 @@
+From 1046e65f7cca2b592fbb7e8f0d1392fb742a67b1 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:48 +0300
+Subject: [PATCH 09/17] psplash.c: Make psplash_draw_{msg,progress} independent
+ of FB
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ psplash.c | 64 ++++++++++++++++++++++++++++---------------------------
+ 1 file changed, 33 insertions(+), 31 deletions(-)
+
+diff --git a/psplash.c b/psplash.c
+index 1a5e543..c234d46 100644
+--- a/psplash.c
++++ b/psplash.c
+@@ -21,11 +21,11 @@
+ #endif
+ #include FONT_HEADER
+
+-#define SPLIT_LINE_POS(fb) \
+- ( (fb)->canvas.height \
+- - (( PSPLASH_IMG_SPLIT_DENOMINATOR \
+- - PSPLASH_IMG_SPLIT_NUMERATOR) \
+- * (fb)->canvas.height / PSPLASH_IMG_SPLIT_DENOMINATOR) \
++#define SPLIT_LINE_POS(canvas) \
++ ( (canvas)->height \
++ - (( PSPLASH_IMG_SPLIT_DENOMINATOR \
++ - PSPLASH_IMG_SPLIT_NUMERATOR) \
++ * (canvas)->height / PSPLASH_IMG_SPLIT_DENOMINATOR) \
+ )
+
+ void
+@@ -37,7 +37,7 @@ psplash_exit (int UNUSED(signum))
+ }
+
+ void
+-psplash_draw_msg (PSplashFB *fb, const char *msg)
++psplash_draw_msg(PSplashCanvas *canvas, const char *msg)
+ {
+ int w, h;
+
+@@ -47,16 +47,16 @@ psplash_draw_msg (PSplashFB *fb, const char *msg)
+
+ /* Clear */
+
+- psplash_draw_rect(&fb->canvas,
++ psplash_draw_rect(canvas,
+ 0,
+- SPLIT_LINE_POS(fb) - h,
+- fb->canvas.width,
++ SPLIT_LINE_POS(canvas) - h,
++ canvas->width,
+ h,
+ PSPLASH_BACKGROUND_COLOR);
+
+- psplash_draw_text(&fb->canvas,
+- (fb->canvas.width-w)/2,
+- SPLIT_LINE_POS(fb) - h,
++ psplash_draw_text(canvas,
++ (canvas->width-w)/2,
++ SPLIT_LINE_POS(canvas) - h,
+ PSPLASH_TEXT_COLOR,
+ &FONT_DEF,
+ msg);
+@@ -64,32 +64,32 @@ psplash_draw_msg (PSplashFB *fb, const char *msg)
+
+ #ifdef PSPLASH_SHOW_PROGRESS_BAR
+ void
+-psplash_draw_progress (PSplashFB *fb, int value)
++psplash_draw_progress(PSplashCanvas *canvas, int value)
+ {
+ int x, y, width, height, barwidth;
+
+ /* 4 pix border */
+- x = ((fb->canvas.width - BAR_IMG_WIDTH)/2) + 4 ;
+- y = SPLIT_LINE_POS(fb) + 4;
++ x = ((canvas->width - BAR_IMG_WIDTH)/2) + 4 ;
++ y = SPLIT_LINE_POS(canvas) + 4;
+ width = BAR_IMG_WIDTH - 8;
+ height = BAR_IMG_HEIGHT - 8;
+
+ if (value > 0)
+ {
+ barwidth = (CLAMP(value,0,100) * width) / 100;
+- psplash_draw_rect(&fb->canvas, x + barwidth, y,
++ psplash_draw_rect(canvas, x + barwidth, y,
+ width - barwidth, height,
+ PSPLASH_BAR_BACKGROUND_COLOR);
+- psplash_draw_rect(&fb->canvas, x, y, barwidth,
++ psplash_draw_rect(canvas, x, y, barwidth,
+ height, PSPLASH_BAR_COLOR);
+ }
+ else
+ {
+ barwidth = (CLAMP(-value,0,100) * width) / 100;
+- psplash_draw_rect(&fb->canvas, x, y,
++ psplash_draw_rect(canvas, x, y,
+ width - barwidth, height,
+ PSPLASH_BAR_BACKGROUND_COLOR);
+- psplash_draw_rect(&fb->canvas, x + width - barwidth,
++ psplash_draw_rect(canvas, x + width - barwidth,
+ y, barwidth, height,
+ PSPLASH_BAR_COLOR);
+ }
+@@ -116,7 +116,7 @@ parse_command (PSplashFB *fb, char *string)
+ char *arg = strtok(NULL, "\0");
+
+ if (arg)
+- psplash_draw_msg (fb, arg);
++ psplash_draw_msg(&fb->canvas, arg);
+ }
+ #ifdef PSPLASH_SHOW_PROGRESS_BAR
+ else if (!strcmp(command,"PROGRESS"))
+@@ -124,7 +124,7 @@ parse_command (PSplashFB *fb, char *string)
+ char *arg = strtok(NULL, "\0");
+
+ if (arg)
+- psplash_draw_progress (fb, atoi(arg));
++ psplash_draw_progress(&fb->canvas, atoi(arg));
+ }
+ #endif
+ else if (!strcmp(command,"QUIT"))
+@@ -226,6 +226,7 @@ main (int argc, char** argv)
+ char *rundir;
+ int pipe_fd, i = 0, angle = 0, fbdev_id = 0, ret = 0;
+ PSplashFB *fb;
++ PSplashCanvas *canvas;
+ bool disable_console_switch = FALSE;
+
+ signal(SIGHUP, psplash_exit);
+@@ -295,22 +296,23 @@ main (int argc, char** argv)
+ ret = -1;
+ goto fb_fail;
+ }
++ canvas = &fb->canvas;
+
+ #ifdef HAVE_SYSTEMD
+ sd_notify(0, "READY=1");
+ #endif
+
+ /* Clear the background with #ecece1 */
+- psplash_draw_rect(&fb->canvas, 0, 0, fb->canvas.width, fb->canvas.height,
++ psplash_draw_rect(canvas, 0, 0, canvas->width, canvas->height,
+ PSPLASH_BACKGROUND_COLOR);
+
+ /* Draw the Poky logo */
+- psplash_draw_image(&fb->canvas,
+- (fb->canvas.width - POKY_IMG_WIDTH)/2,
++ psplash_draw_image(canvas,
++ (canvas->width - POKY_IMG_WIDTH)/2,
+ #if PSPLASH_IMG_FULLSCREEN
+- (fb->canvas.height - POKY_IMG_HEIGHT)/2,
++ (canvas->height - POKY_IMG_HEIGHT)/2,
+ #else
+- (fb->canvas.height * PSPLASH_IMG_SPLIT_NUMERATOR
++ (canvas->height * PSPLASH_IMG_SPLIT_NUMERATOR
+ / PSPLASH_IMG_SPLIT_DENOMINATOR - POKY_IMG_HEIGHT)/2,
+ #endif
+ POKY_IMG_WIDTH,
+@@ -321,20 +323,20 @@ main (int argc, char** argv)
+
+ #ifdef PSPLASH_SHOW_PROGRESS_BAR
+ /* Draw progress bar border */
+- psplash_draw_image(&fb->canvas,
+- (fb->canvas.width - BAR_IMG_WIDTH)/2,
+- SPLIT_LINE_POS(fb),
++ psplash_draw_image(canvas,
++ (canvas->width - BAR_IMG_WIDTH)/2,
++ SPLIT_LINE_POS(canvas),
+ BAR_IMG_WIDTH,
+ BAR_IMG_HEIGHT,
+ BAR_IMG_BYTES_PER_PIXEL,
+ BAR_IMG_ROWSTRIDE,
+ BAR_IMG_RLE_PIXEL_DATA);
+
+- psplash_draw_progress (fb, 0);
++ psplash_draw_progress(canvas, 0);
+ #endif
+
+ #ifdef PSPLASH_STARTUP_MSG
+- psplash_draw_msg (fb, PSPLASH_STARTUP_MSG);
++ psplash_draw_msg(canvas, PSPLASH_STARTUP_MSG);
+ #endif
+
+ /* Scene set so let's flip the buffers. */
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0010-Rework-flip-as-function-pointer.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0010-Rework-flip-as-function-pointer.patch
new file mode 100644
index 00000000..2d897a37
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0010-Rework-flip-as-function-pointer.patch
@@ -0,0 +1,141 @@
+From e1004cd1a1252a17219f5ebd13749c91e8ddc09b Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:49 +0300
+Subject: [PATCH 10/17] Rework flip as function pointer
+
+It allows making parse_command and psplash_main independent of FB.
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ psplash-draw.h | 3 +++
+ psplash-fb.c | 8 +++++---
+ psplash-fb.h | 3 ---
+ psplash.c | 16 ++++++++--------
+ 4 files changed, 16 insertions(+), 14 deletions(-)
+
+diff --git a/psplash-draw.h b/psplash-draw.h
+index 44546b0..292ddd9 100644
+--- a/psplash-draw.h
++++ b/psplash-draw.h
+@@ -36,6 +36,9 @@ typedef struct PSplashCanvas
+ int green_length;
+ int blue_offset;
+ int blue_length;
++
++ void *priv;
++ void (*flip)(struct PSplashCanvas *canvas, int sync);
+ }
+ PSplashCanvas;
+
+diff --git a/psplash-fb.c b/psplash-fb.c
+index dd50a5a..d41c477 100644
+--- a/psplash-fb.c
++++ b/psplash-fb.c
+@@ -18,9 +18,10 @@ psplash_wait_for_vsync(PSplashFB *fb)
+ fprintf(stderr, "Error, FB vsync ioctl [%d]\n", err);
+ }
+
+-void
+-psplash_fb_flip(PSplashFB *fb, int sync)
++static void
++psplash_fb_flip(PSplashCanvas *canvas, int sync)
+ {
++ PSplashFB *fb = canvas->priv;
+ char *tmp;
+
+ if (fb->double_buffering) {
+@@ -154,7 +155,8 @@ psplash_fb_new (int angle, int fbdev_id)
+ }
+
+ memset (fb, 0, sizeof(PSplashFB));
+-
++ fb->canvas.priv = fb;
++ fb->canvas.flip = psplash_fb_flip;
+ fb->fd = -1;
+
+ if ((fb->fd = open (fbdev, O_RDWR)) < 0)
+diff --git a/psplash-fb.h b/psplash-fb.h
+index 1b16bd5..979d23a 100644
+--- a/psplash-fb.h
++++ b/psplash-fb.h
+@@ -40,7 +40,4 @@ psplash_fb_destroy (PSplashFB *fb);
+ PSplashFB*
+ psplash_fb_new (int angle, int fbdev_id);
+
+-void
+-psplash_fb_flip(PSplashFB *fb, int sync);
+-
+ #endif
+diff --git a/psplash.c b/psplash.c
+index c234d46..036dfb1 100644
+--- a/psplash.c
++++ b/psplash.c
+@@ -100,7 +100,7 @@ psplash_draw_progress(PSplashCanvas *canvas, int value)
+ #endif /* PSPLASH_SHOW_PROGRESS_BAR */
+
+ static int
+-parse_command (PSplashFB *fb, char *string)
++parse_command(PSplashCanvas *canvas, char *string)
+ {
+ char *command;
+
+@@ -116,7 +116,7 @@ parse_command (PSplashFB *fb, char *string)
+ char *arg = strtok(NULL, "\0");
+
+ if (arg)
+- psplash_draw_msg(&fb->canvas, arg);
++ psplash_draw_msg(canvas, arg);
+ }
+ #ifdef PSPLASH_SHOW_PROGRESS_BAR
+ else if (!strcmp(command,"PROGRESS"))
+@@ -124,7 +124,7 @@ parse_command (PSplashFB *fb, char *string)
+ char *arg = strtok(NULL, "\0");
+
+ if (arg)
+- psplash_draw_progress(&fb->canvas, atoi(arg));
++ psplash_draw_progress(canvas, atoi(arg));
+ }
+ #endif
+ else if (!strcmp(command,"QUIT"))
+@@ -132,12 +132,12 @@ parse_command (PSplashFB *fb, char *string)
+ return 1;
+ }
+
+- psplash_fb_flip(fb, 0);
++ canvas->flip(canvas, 0);
+ return 0;
+ }
+
+ void
+-psplash_main (PSplashFB *fb, int pipe_fd, int timeout)
++psplash_main(PSplashCanvas *canvas, int pipe_fd, int timeout)
+ {
+ int err;
+ ssize_t length = 0;
+@@ -200,7 +200,7 @@ psplash_main (PSplashFB *fb, int pipe_fd, int timeout)
+ continue;
+ }
+
+- if (parse_command(fb, cmd))
++ if (parse_command(canvas, cmd))
+ return;
+
+ length -= cmdlen;
+@@ -345,9 +345,9 @@ main (int argc, char** argv)
+ * text and progress bar change which overwrite the specific areas with every
+ * update.
+ */
+- psplash_fb_flip(fb, 1);
++ canvas->flip(canvas, 1);
+
+- psplash_main (fb, pipe_fd, 0);
++ psplash_main(canvas, pipe_fd, 0);
+
+ psplash_fb_destroy (fb);
+
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0011-Import-drm-howto-modeset.c-as-psplash-drm.c.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0011-Import-drm-howto-modeset.c-as-psplash-drm.c.patch
new file mode 100644
index 00000000..767dbf4b
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0011-Import-drm-howto-modeset.c-as-psplash-drm.c.patch
@@ -0,0 +1,764 @@
+From d5a9fb5cd8505c16d4d75c695af1e64597d36c86 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:50 +0300
+Subject: [PATCH 11/17] Import drm-howto modeset.c as psplash-drm.c
+
+Imported as is from
+repo: https://github.com/dvdhrm/docs.git
+branch: master
+commit: fc5c63f
+path: drm-howto/modeset.c
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ psplash-drm.c | 735 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 735 insertions(+)
+ create mode 100644 psplash-drm.c
+
+diff --git a/psplash-drm.c b/psplash-drm.c
+new file mode 100644
+index 0000000..c9a9f5c
+--- /dev/null
++++ b/psplash-drm.c
+@@ -0,0 +1,735 @@
++/*
++ * modeset - DRM Modesetting Example
++ *
++ * Written 2012 by David Rheinsberg <david.rheinsberg@gmail.com>
++ * Dedicated to the Public Domain.
++ */
++
++/*
++ * DRM Modesetting Howto
++ * This document describes the DRM modesetting API. Before we can use the DRM
++ * API, we have to include xf86drm.h and xf86drmMode.h. Both are provided by
++ * libdrm which every major distribution ships by default. It has no other
++ * dependencies and is pretty small.
++ *
++ * Please ignore all forward-declarations of functions which are used later. I
++ * reordered the functions so you can read this document from top to bottom. If
++ * you reimplement it, you would probably reorder the functions to avoid all the
++ * nasty forward declarations.
++ *
++ * For easier reading, we ignore all memory-allocation errors of malloc() and
++ * friends here. However, we try to correctly handle all other kinds of errors
++ * that may occur.
++ *
++ * All functions and global variables are prefixed with "modeset_*" in this
++ * file. So it should be clear whether a function is a local helper or if it is
++ * provided by some external library.
++ */
++
++#define _GNU_SOURCE
++#include <errno.h>
++#include <fcntl.h>
++#include <stdbool.h>
++#include <stdint.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/mman.h>
++#include <time.h>
++#include <unistd.h>
++#include <xf86drm.h>
++#include <xf86drmMode.h>
++
++struct modeset_dev;
++static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
++ struct modeset_dev *dev);
++static int modeset_create_fb(int fd, struct modeset_dev *dev);
++static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
++ struct modeset_dev *dev);
++static int modeset_open(int *out, const char *node);
++static int modeset_prepare(int fd);
++static void modeset_draw(void);
++static void modeset_cleanup(int fd);
++
++/*
++ * When the linux kernel detects a graphics-card on your machine, it loads the
++ * correct device driver (located in kernel-tree at ./drivers/gpu/drm/<xy>) and
++ * provides two character-devices to control it. Udev (or whatever hotplugging
++ * application you use) will create them as:
++ * /dev/dri/card0
++ * /dev/dri/controlID64
++ * We only need the first one. You can hard-code this path into your application
++ * like we do here, but it is recommended to use libudev with real hotplugging
++ * and multi-seat support. However, this is beyond the scope of this document.
++ * Also note that if you have multiple graphics-cards, there may also be
++ * /dev/dri/card1, /dev/dri/card2, ...
++ *
++ * We simply use /dev/dri/card0 here but the user can specify another path on
++ * the command line.
++ *
++ * modeset_open(out, node): This small helper function opens the DRM device
++ * which is given as @node. The new fd is stored in @out on success. On failure,
++ * a negative error code is returned.
++ * After opening the file, we also check for the DRM_CAP_DUMB_BUFFER capability.
++ * If the driver supports this capability, we can create simple memory-mapped
++ * buffers without any driver-dependent code. As we want to avoid any radeon,
++ * nvidia, intel, etc. specific code, we depend on DUMB_BUFFERs here.
++ */
++
++static int modeset_open(int *out, const char *node)
++{
++ int fd, ret;
++ uint64_t has_dumb;
++
++ fd = open(node, O_RDWR | O_CLOEXEC);
++ if (fd < 0) {
++ ret = -errno;
++ fprintf(stderr, "cannot open '%s': %m\n", node);
++ return ret;
++ }
++
++ if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 ||
++ !has_dumb) {
++ fprintf(stderr, "drm device '%s' does not support dumb buffers\n",
++ node);
++ close(fd);
++ return -EOPNOTSUPP;
++ }
++
++ *out = fd;
++ return 0;
++}
++
++/*
++ * As a next step we need to find our available display devices. libdrm provides
++ * a drmModeRes structure that contains all the needed information. We can
++ * retrieve it via drmModeGetResources(fd) and free it via
++ * drmModeFreeResources(res) again.
++ *
++ * A physical connector on your graphics card is called a "connector". You can
++ * plug a monitor into it and control what is displayed. We are definitely
++ * interested in what connectors are currently used, so we simply iterate
++ * through the list of connectors and try to display a test-picture on each
++ * available monitor.
++ * However, this isn't as easy as it sounds. First, we need to check whether the
++ * connector is actually used (a monitor is plugged in and turned on). Then we
++ * need to find a CRTC that can control this connector. CRTCs are described
++ * later on. After that we create a framebuffer object. If we have all this, we
++ * can mmap() the framebuffer and draw a test-picture into it. Then we can tell
++ * the DRM device to show the framebuffer on the given CRTC with the selected
++ * connector.
++ *
++ * As we want to draw moving pictures on the framebuffer, we actually have to
++ * remember all these settings. Therefore, we create one "struct modeset_dev"
++ * object for each connector+crtc+framebuffer pair that we successfully
++ * initialized and push it into the global device-list.
++ *
++ * Each field of this structure is described when it is first used. But as a
++ * summary:
++ * "struct modeset_dev" contains: {
++ * - @next: points to the next device in the single-linked list
++ *
++ * - @width: width of our buffer object
++ * - @height: height of our buffer object
++ * - @stride: stride value of our buffer object
++ * - @size: size of the memory mapped buffer
++ * - @handle: a DRM handle to the buffer object that we can draw into
++ * - @map: pointer to the memory mapped buffer
++ *
++ * - @mode: the display mode that we want to use
++ * - @fb: a framebuffer handle with our buffer object as scanout buffer
++ * - @conn: the connector ID that we want to use with this buffer
++ * - @crtc: the crtc ID that we want to use with this connector
++ * - @saved_crtc: the configuration of the crtc before we changed it. We use it
++ * so we can restore the same mode when we exit.
++ * }
++ */
++
++struct modeset_dev {
++ struct modeset_dev *next;
++
++ uint32_t width;
++ uint32_t height;
++ uint32_t stride;
++ uint32_t size;
++ uint32_t handle;
++ uint8_t *map;
++
++ drmModeModeInfo mode;
++ uint32_t fb;
++ uint32_t conn;
++ uint32_t crtc;
++ drmModeCrtc *saved_crtc;
++};
++
++static struct modeset_dev *modeset_list = NULL;
++
++/*
++ * So as next step we need to actually prepare all connectors that we find. We
++ * do this in this little helper function:
++ *
++ * modeset_prepare(fd): This helper function takes the DRM fd as argument and
++ * then simply retrieves the resource-info from the device. It then iterates
++ * through all connectors and calls other helper functions to initialize this
++ * connector (described later on).
++ * If the initialization was successful, we simply add this object as new device
++ * into the global modeset device list.
++ *
++ * The resource-structure contains a list of all connector-IDs. We use the
++ * helper function drmModeGetConnector() to retrieve more information on each
++ * connector. After we are done with it, we free it again with
++ * drmModeFreeConnector().
++ * Our helper modeset_setup_dev() returns -ENOENT if the connector is currently
++ * unused and no monitor is plugged in. So we can ignore this connector.
++ */
++
++static int modeset_prepare(int fd)
++{
++ drmModeRes *res;
++ drmModeConnector *conn;
++ unsigned int i;
++ struct modeset_dev *dev;
++ int ret;
++
++ /* retrieve resources */
++ res = drmModeGetResources(fd);
++ if (!res) {
++ fprintf(stderr, "cannot retrieve DRM resources (%d): %m\n",
++ errno);
++ return -errno;
++ }
++
++ /* iterate all connectors */
++ for (i = 0; i < res->count_connectors; ++i) {
++ /* get information for each connector */
++ conn = drmModeGetConnector(fd, res->connectors[i]);
++ if (!conn) {
++ fprintf(stderr, "cannot retrieve DRM connector %u:%u (%d): %m\n",
++ i, res->connectors[i], errno);
++ continue;
++ }
++
++ /* create a device structure */
++ dev = malloc(sizeof(*dev));
++ memset(dev, 0, sizeof(*dev));
++ dev->conn = conn->connector_id;
++
++ /* call helper function to prepare this connector */
++ ret = modeset_setup_dev(fd, res, conn, dev);
++ if (ret) {
++ if (ret != -ENOENT) {
++ errno = -ret;
++ fprintf(stderr, "cannot setup device for connector %u:%u (%d): %m\n",
++ i, res->connectors[i], errno);
++ }
++ free(dev);
++ drmModeFreeConnector(conn);
++ continue;
++ }
++
++ /* free connector data and link device into global list */
++ drmModeFreeConnector(conn);
++ dev->next = modeset_list;
++ modeset_list = dev;
++ }
++
++ /* free resources again */
++ drmModeFreeResources(res);
++ return 0;
++}
++
++/*
++ * Now we dig deeper into setting up a single connector. As described earlier,
++ * we need to check several things first:
++ * * If the connector is currently unused, that is, no monitor is plugged in,
++ * then we can ignore it.
++ * * We have to find a suitable resolution and refresh-rate. All this is
++ * available in drmModeModeInfo structures saved for each crtc. We simply
++ * use the first mode that is available. This is always the mode with the
++ * highest resolution.
++ * A more sophisticated mode-selection should be done in real applications,
++ * though.
++ * * Then we need to find an CRTC that can drive this connector. A CRTC is an
++ * internal resource of each graphics-card. The number of CRTCs controls how
++ * many connectors can be controlled indepedently. That is, a graphics-cards
++ * may have more connectors than CRTCs, which means, not all monitors can be
++ * controlled independently.
++ * There is actually the possibility to control multiple connectors via a
++ * single CRTC if the monitors should display the same content. However, we
++ * do not make use of this here.
++ * So think of connectors as pipelines to the connected monitors and the
++ * CRTCs are the controllers that manage which data goes to which pipeline.
++ * If there are more pipelines than CRTCs, then we cannot control all of
++ * them at the same time.
++ * * We need to create a framebuffer for this connector. A framebuffer is a
++ * memory buffer that we can write XRGB32 data into. So we use this to
++ * render our graphics and then the CRTC can scan-out this data from the
++ * framebuffer onto the monitor.
++ */
++
++static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
++ struct modeset_dev *dev)
++{
++ int ret;
++
++ /* check if a monitor is connected */
++ if (conn->connection != DRM_MODE_CONNECTED) {
++ fprintf(stderr, "ignoring unused connector %u\n",
++ conn->connector_id);
++ return -ENOENT;
++ }
++
++ /* check if there is at least one valid mode */
++ if (conn->count_modes == 0) {
++ fprintf(stderr, "no valid mode for connector %u\n",
++ conn->connector_id);
++ return -EFAULT;
++ }
++
++ /* copy the mode information into our device structure */
++ memcpy(&dev->mode, &conn->modes[0], sizeof(dev->mode));
++ dev->width = conn->modes[0].hdisplay;
++ dev->height = conn->modes[0].vdisplay;
++ fprintf(stderr, "mode for connector %u is %ux%u\n",
++ conn->connector_id, dev->width, dev->height);
++
++ /* find a crtc for this connector */
++ ret = modeset_find_crtc(fd, res, conn, dev);
++ if (ret) {
++ fprintf(stderr, "no valid crtc for connector %u\n",
++ conn->connector_id);
++ return ret;
++ }
++
++ /* create a framebuffer for this CRTC */
++ ret = modeset_create_fb(fd, dev);
++ if (ret) {
++ fprintf(stderr, "cannot create framebuffer for connector %u\n",
++ conn->connector_id);
++ return ret;
++ }
++
++ return 0;
++}
++
++/*
++ * modeset_find_crtc(fd, res, conn, dev): This small helper tries to find a
++ * suitable CRTC for the given connector. We have actually have to introduce one
++ * more DRM object to make this more clear: Encoders.
++ * Encoders help the CRTC to convert data from a framebuffer into the right
++ * format that can be used for the chosen connector. We do not have to
++ * understand any more of these conversions to make use of it. However, you must
++ * know that each connector has a limited list of encoders that it can use. And
++ * each encoder can only work with a limited list of CRTCs. So what we do is
++ * trying each encoder that is available and looking for a CRTC that this
++ * encoder can work with. If we find the first working combination, we are happy
++ * and write it into the @dev structure.
++ * But before iterating all available encoders, we first try the currently
++ * active encoder+crtc on a connector to avoid a full modeset.
++ *
++ * However, before we can use a CRTC we must make sure that no other device,
++ * that we setup previously, is already using this CRTC. Remember, we can only
++ * drive one connector per CRTC! So we simply iterate through the "modeset_list"
++ * of previously setup devices and check that this CRTC wasn't used before.
++ * Otherwise, we continue with the next CRTC/Encoder combination.
++ */
++
++static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
++ struct modeset_dev *dev)
++{
++ drmModeEncoder *enc;
++ unsigned int i, j;
++ int32_t crtc;
++ struct modeset_dev *iter;
++
++ /* first try the currently conected encoder+crtc */
++ if (conn->encoder_id)
++ enc = drmModeGetEncoder(fd, conn->encoder_id);
++ else
++ enc = NULL;
++
++ if (enc) {
++ if (enc->crtc_id) {
++ crtc = enc->crtc_id;
++ for (iter = modeset_list; iter; iter = iter->next) {
++ if (iter->crtc == crtc) {
++ crtc = -1;
++ break;
++ }
++ }
++
++ if (crtc >= 0) {
++ drmModeFreeEncoder(enc);
++ dev->crtc = crtc;
++ return 0;
++ }
++ }
++
++ drmModeFreeEncoder(enc);
++ }
++
++ /* If the connector is not currently bound to an encoder or if the
++ * encoder+crtc is already used by another connector (actually unlikely
++ * but lets be safe), iterate all other available encoders to find a
++ * matching CRTC. */
++ for (i = 0; i < conn->count_encoders; ++i) {
++ enc = drmModeGetEncoder(fd, conn->encoders[i]);
++ if (!enc) {
++ fprintf(stderr, "cannot retrieve encoder %u:%u (%d): %m\n",
++ i, conn->encoders[i], errno);
++ continue;
++ }
++
++ /* iterate all global CRTCs */
++ for (j = 0; j < res->count_crtcs; ++j) {
++ /* check whether this CRTC works with the encoder */
++ if (!(enc->possible_crtcs & (1 << j)))
++ continue;
++
++ /* check that no other device already uses this CRTC */
++ crtc = res->crtcs[j];
++ for (iter = modeset_list; iter; iter = iter->next) {
++ if (iter->crtc == crtc) {
++ crtc = -1;
++ break;
++ }
++ }
++
++ /* we have found a CRTC, so save it and return */
++ if (crtc >= 0) {
++ drmModeFreeEncoder(enc);
++ dev->crtc = crtc;
++ return 0;
++ }
++ }
++
++ drmModeFreeEncoder(enc);
++ }
++
++ fprintf(stderr, "cannot find suitable CRTC for connector %u\n",
++ conn->connector_id);
++ return -ENOENT;
++}
++
++/*
++ * modeset_create_fb(fd, dev): After we have found a crtc+connector+mode
++ * combination, we need to actually create a suitable framebuffer that we can
++ * use with it. There are actually two ways to do that:
++ * * We can create a so called "dumb buffer". This is a buffer that we can
++ * memory-map via mmap() and every driver supports this. We can use it for
++ * unaccelerated software rendering on the CPU.
++ * * We can use libgbm to create buffers available for hardware-acceleration.
++ * libgbm is an abstraction layer that creates these buffers for each
++ * available DRM driver. As there is no generic API for this, each driver
++ * provides its own way to create these buffers.
++ * We can then use such buffers to create OpenGL contexts with the mesa3D
++ * library.
++ * We use the first solution here as it is much simpler and doesn't require any
++ * external libraries. However, if you want to use hardware-acceleration via
++ * OpenGL, it is actually pretty easy to create such buffers with libgbm and
++ * libEGL. But this is beyond the scope of this document.
++ *
++ * So what we do is requesting a new dumb-buffer from the driver. We specify the
++ * same size as the current mode that we selected for the connector.
++ * Then we request the driver to prepare this buffer for memory mapping. After
++ * that we perform the actual mmap() call. So we can now access the framebuffer
++ * memory directly via the dev->map memory map.
++ */
++
++static int modeset_create_fb(int fd, struct modeset_dev *dev)
++{
++ struct drm_mode_create_dumb creq;
++ struct drm_mode_destroy_dumb dreq;
++ struct drm_mode_map_dumb mreq;
++ int ret;
++
++ /* create dumb buffer */
++ memset(&creq, 0, sizeof(creq));
++ creq.width = dev->width;
++ creq.height = dev->height;
++ creq.bpp = 32;
++ ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
++ if (ret < 0) {
++ fprintf(stderr, "cannot create dumb buffer (%d): %m\n",
++ errno);
++ return -errno;
++ }
++ dev->stride = creq.pitch;
++ dev->size = creq.size;
++ dev->handle = creq.handle;
++
++ /* create framebuffer object for the dumb-buffer */
++ ret = drmModeAddFB(fd, dev->width, dev->height, 24, 32, dev->stride,
++ dev->handle, &dev->fb);
++ if (ret) {
++ fprintf(stderr, "cannot create framebuffer (%d): %m\n",
++ errno);
++ ret = -errno;
++ goto err_destroy;
++ }
++
++ /* prepare buffer for memory mapping */
++ memset(&mreq, 0, sizeof(mreq));
++ mreq.handle = dev->handle;
++ ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
++ if (ret) {
++ fprintf(stderr, "cannot map dumb buffer (%d): %m\n",
++ errno);
++ ret = -errno;
++ goto err_fb;
++ }
++
++ /* perform actual memory mapping */
++ dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED,
++ fd, mreq.offset);
++ if (dev->map == MAP_FAILED) {
++ fprintf(stderr, "cannot mmap dumb buffer (%d): %m\n",
++ errno);
++ ret = -errno;
++ goto err_fb;
++ }
++
++ /* clear the framebuffer to 0 */
++ memset(dev->map, 0, dev->size);
++
++ return 0;
++
++err_fb:
++ drmModeRmFB(fd, dev->fb);
++err_destroy:
++ memset(&dreq, 0, sizeof(dreq));
++ dreq.handle = dev->handle;
++ drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
++ return ret;
++}
++
++/*
++ * Finally! We have a connector with a suitable CRTC. We know which mode we want
++ * to use and we have a framebuffer of the correct size that we can write to.
++ * There is nothing special left to do. We only have to program the CRTC to
++ * connect each new framebuffer to each selected connector for each combination
++ * that we saved in the global modeset_list.
++ * This is done with a call to drmModeSetCrtc().
++ *
++ * So we are ready for our main() function. First we check whether the user
++ * specified a DRM device on the command line, otherwise we use the default
++ * /dev/dri/card0. Then we open the device via modeset_open(). modeset_prepare()
++ * prepares all connectors and we can loop over "modeset_list" and call
++ * drmModeSetCrtc() on every CRTC/connector combination.
++ *
++ * But printing empty black pages is boring so we have another helper function
++ * modeset_draw() that draws some colors into the framebuffer for 5 seconds and
++ * then returns. And then we have all the cleanup functions which correctly free
++ * all devices again after we used them. All these functions are described below
++ * the main() function.
++ *
++ * As a side note: drmModeSetCrtc() actually takes a list of connectors that we
++ * want to control with this CRTC. We pass only one connector, though. As
++ * explained earlier, if we used multiple connectors, then all connectors would
++ * have the same controlling framebuffer so the output would be cloned. This is
++ * most often not what you want so we avoid explaining this feature here.
++ * Furthermore, all connectors will have to run with the same mode, which is
++ * also often not guaranteed. So instead, we only use one connector per CRTC.
++ *
++ * Before calling drmModeSetCrtc() we also save the current CRTC configuration.
++ * This is used in modeset_cleanup() to restore the CRTC to the same mode as was
++ * before we changed it.
++ * If we don't do this, the screen will stay blank after we exit until another
++ * application performs modesetting itself.
++ */
++
++int main(int argc, char **argv)
++{
++ int ret, fd;
++ const char *card;
++ struct modeset_dev *iter;
++
++ /* check which DRM device to open */
++ if (argc > 1)
++ card = argv[1];
++ else
++ card = "/dev/dri/card0";
++
++ fprintf(stderr, "using card '%s'\n", card);
++
++ /* open the DRM device */
++ ret = modeset_open(&fd, card);
++ if (ret)
++ goto out_return;
++
++ /* prepare all connectors and CRTCs */
++ ret = modeset_prepare(fd);
++ if (ret)
++ goto out_close;
++
++ /* perform actual modesetting on each found connector+CRTC */
++ for (iter = modeset_list; iter; iter = iter->next) {
++ iter->saved_crtc = drmModeGetCrtc(fd, iter->crtc);
++ ret = drmModeSetCrtc(fd, iter->crtc, iter->fb, 0, 0,
++ &iter->conn, 1, &iter->mode);
++ if (ret)
++ fprintf(stderr, "cannot set CRTC for connector %u (%d): %m\n",
++ iter->conn, errno);
++ }
++
++ /* draw some colors for 5seconds */
++ modeset_draw();
++
++ /* cleanup everything */
++ modeset_cleanup(fd);
++
++ ret = 0;
++
++out_close:
++ close(fd);
++out_return:
++ if (ret) {
++ errno = -ret;
++ fprintf(stderr, "modeset failed with error %d: %m\n", errno);
++ } else {
++ fprintf(stderr, "exiting\n");
++ }
++ return ret;
++}
++
++/*
++ * A short helper function to compute a changing color value. No need to
++ * understand it.
++ */
++
++static uint8_t next_color(bool *up, uint8_t cur, unsigned int mod)
++{
++ uint8_t next;
++
++ next = cur + (*up ? 1 : -1) * (rand() % mod);
++ if ((*up && next < cur) || (!*up && next > cur)) {
++ *up = !*up;
++ next = cur;
++ }
++
++ return next;
++}
++
++/*
++ * modeset_draw(): This draws a solid color into all configured framebuffers.
++ * Every 100ms the color changes to a slightly different color so we get some
++ * kind of smoothly changing color-gradient.
++ *
++ * The color calculation can be ignored as it is pretty boring. So the
++ * interesting stuff is iterating over "modeset_list" and then through all lines
++ * and width. We then set each pixel individually to the current color.
++ *
++ * We do this 50 times as we sleep 100ms after each redraw round. This makes
++ * 50*100ms = 5000ms = 5s so it takes about 5seconds to finish this loop.
++ *
++ * Please note that we draw directly into the framebuffer. This means that you
++ * will see flickering as the monitor might refresh while we redraw the screen.
++ * To avoid this you would need to use two framebuffers and a call to
++ * drmModeSetCrtc() to switch between both buffers.
++ * You can also use drmModePageFlip() to do a vsync'ed pageflip. But this is
++ * beyond the scope of this document.
++ */
++
++static void modeset_draw(void)
++{
++ uint8_t r, g, b;
++ bool r_up, g_up, b_up;
++ unsigned int i, j, k, off;
++ struct modeset_dev *iter;
++
++ srand(time(NULL));
++ r = rand() % 0xff;
++ g = rand() % 0xff;
++ b = rand() % 0xff;
++ r_up = g_up = b_up = true;
++
++ for (i = 0; i < 50; ++i) {
++ r = next_color(&r_up, r, 20);
++ g = next_color(&g_up, g, 10);
++ b = next_color(&b_up, b, 5);
++
++ for (iter = modeset_list; iter; iter = iter->next) {
++ for (j = 0; j < iter->height; ++j) {
++ for (k = 0; k < iter->width; ++k) {
++ off = iter->stride * j + k * 4;
++ *(uint32_t*)&iter->map[off] =
++ (r << 16) | (g << 8) | b;
++ }
++ }
++ }
++
++ usleep(100000);
++ }
++}
++
++/*
++ * modeset_cleanup(fd): This cleans up all the devices we created during
++ * modeset_prepare(). It resets the CRTCs to their saved states and deallocates
++ * all memory.
++ * It should be pretty obvious how all of this works.
++ */
++
++static void modeset_cleanup(int fd)
++{
++ struct modeset_dev *iter;
++ struct drm_mode_destroy_dumb dreq;
++
++ while (modeset_list) {
++ /* remove from global list */
++ iter = modeset_list;
++ modeset_list = iter->next;
++
++ /* restore saved CRTC configuration */
++ drmModeSetCrtc(fd,
++ iter->saved_crtc->crtc_id,
++ iter->saved_crtc->buffer_id,
++ iter->saved_crtc->x,
++ iter->saved_crtc->y,
++ &iter->conn,
++ 1,
++ &iter->saved_crtc->mode);
++ drmModeFreeCrtc(iter->saved_crtc);
++
++ /* unmap buffer */
++ munmap(iter->map, iter->size);
++
++ /* delete framebuffer */
++ drmModeRmFB(fd, iter->fb);
++
++ /* delete dumb buffer */
++ memset(&dreq, 0, sizeof(dreq));
++ dreq.handle = iter->handle;
++ drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
++
++ /* free allocated memory */
++ free(iter);
++ }
++}
++
++/*
++ * I hope this was a short but easy overview of the DRM modesetting API. The DRM
++ * API offers much more capabilities including:
++ * - double-buffering or tripple-buffering (or whatever you want)
++ * - vsync'ed page-flips
++ * - hardware-accelerated rendering (for example via OpenGL)
++ * - output cloning
++ * - graphics-clients plus authentication
++ * - DRM planes/overlays/sprites
++ * - ...
++ * If you are interested in these topics, I can currently only redirect you to
++ * existing implementations, including:
++ * - plymouth (which uses dumb-buffers like this example; very easy to understand)
++ * - kmscon (which uses libuterm to do this)
++ * - wayland (very sophisticated DRM renderer; hard to understand fully as it
++ * uses more complicated techniques like DRM planes)
++ * - xserver (very hard to understand as it is split across many files/projects)
++ *
++ * But understanding how modesetting (as described in this document) works, is
++ * essential to understand all further DRM topics.
++ *
++ * Any feedback is welcome. Feel free to use this code freely for your own
++ * documentation or projects.
++ *
++ * - Hosted on http://github.com/dvdhrm/docs
++ * - Written by David Rheinsberg <david.rheinsberg@gmail.com>
++ */
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0012-Implement-drm-backend.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0012-Implement-drm-backend.patch
new file mode 100644
index 00000000..1d1e281d
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0012-Implement-drm-backend.patch
@@ -0,0 +1,507 @@
+From edc84300b5e5d8b15a87fbb4aee0c83e1a80e9e6 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:51 +0300
+Subject: [PATCH 12/17] Implement drm backend
+
+Limitation is that splash screen is drawn only on the first connector.
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ Makefile.am | 12 +++-
+ configure.ac | 9 +++
+ psplash-drm.c | 179 +++++++++++++++++---------------------------------
+ psplash-drm.h | 17 +++++
+ psplash.c | 52 +++++++++++----
+ 5 files changed, 135 insertions(+), 134 deletions(-)
+ create mode 100644 psplash-drm.h
+
+diff --git a/Makefile.am b/Makefile.am
+index 375b926..c3d4f03 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -8,12 +8,20 @@ psplash_SOURCES = psplash.c psplash.h psplash-fb.c psplash-fb.h \
+ psplash-poky-img.h psplash-bar-img.h $(FONT_NAME)-font.h \
+ psplash-draw.c psplash-draw.h
+ BUILT_SOURCES = psplash-poky-img.h psplash-bar-img.h
++psplash_CPPFLAGS =
++psplash_LDFLAGS =
+
+ psplash_write_SOURCES = psplash-write.c psplash.h
+
++if ENABLE_DRM
++psplash_SOURCES += psplash-drm.c psplash-drm.h
++psplash_CPPFLAGS += $(LIBDRM_CFLAGS) -DENABLE_DRM
++psplash_LDFLAGS += $(LIBDRM_LIBS)
++endif
++
+ if HAVE_SYSTEMD
+-psplash_CPPFLAGS = $(SYSTEMD_CFLAGS) -DHAVE_SYSTEMD
+-psplash_LDFLAGS= $(SYSTEMD_LIBS)
++psplash_CPPFLAGS += $(SYSTEMD_CFLAGS) -DHAVE_SYSTEMD
++psplash_LDFLAGS += $(SYSTEMD_LIBS)
+ bin_PROGRAMS += psplash-systemd
+ psplash_systemd_CPPFLAGS = $(SYSTEMD_CFLAGS)
+ psplash_systemd_LDFLAGS= $(SYSTEMD_LIBS)
+diff --git a/configure.ac b/configure.ac
+index 2a7da91..2e5c4f5 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -12,6 +12,15 @@ if test "x$GCC" = "xyes"; then
+ GCC_FLAGS="-g -Wall -Wextra"
+ fi
+
++AC_ARG_ENABLE(drm,
++ AS_HELP_STRING([--enable-drm], [enable drm backend (default is 'no')]))
++
++AS_IF([test "x$enable_drm" = "xyes"], [
++ PKG_CHECK_MODULES(LIBDRM, libdrm)
++])
++
++AM_CONDITIONAL([ENABLE_DRM], [test "x$enable_drm" = "xyes"])
++
+ AC_ARG_WITH([systemd], AS_HELP_STRING([--with-systemd], [Build with systemd
+ support]))
+
+diff --git a/psplash-drm.c b/psplash-drm.c
+index c9a9f5c..30850ed 100644
+--- a/psplash-drm.c
++++ b/psplash-drm.c
+@@ -26,10 +26,8 @@
+ * provided by some external library.
+ */
+
+-#define _GNU_SOURCE
+ #include <errno.h>
+ #include <fcntl.h>
+-#include <stdbool.h>
+ #include <stdint.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -39,6 +37,7 @@
+ #include <unistd.h>
+ #include <xf86drm.h>
+ #include <xf86drmMode.h>
++#include "psplash-drm.h"
+
+ struct modeset_dev;
+ static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
+@@ -48,8 +47,6 @@ static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
+ struct modeset_dev *dev);
+ static int modeset_open(int *out, const char *node);
+ static int modeset_prepare(int fd);
+-static void modeset_draw(void);
+-static void modeset_cleanup(int fd);
+
+ /*
+ * When the linux kernel detects a graphics-card on your machine, it loads the
+@@ -153,7 +150,7 @@ struct modeset_dev {
+ uint32_t stride;
+ uint32_t size;
+ uint32_t handle;
+- uint8_t *map;
++ void *map;
+
+ drmModeModeInfo mode;
+ uint32_t fb;
+@@ -187,7 +184,7 @@ static int modeset_prepare(int fd)
+ {
+ drmModeRes *res;
+ drmModeConnector *conn;
+- unsigned int i;
++ int i;
+ struct modeset_dev *dev;
+ int ret;
+
+@@ -338,11 +335,10 @@ static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
+ struct modeset_dev *dev)
+ {
+ drmModeEncoder *enc;
+- unsigned int i, j;
+- int32_t crtc;
++ int i, j, crtc;
+ struct modeset_dev *iter;
+
+- /* first try the currently conected encoder+crtc */
++ /* first try the currently connected encoder+crtc */
+ if (conn->encoder_id)
+ enc = drmModeGetEncoder(fd, conn->encoder_id);
+ else
+@@ -352,7 +348,7 @@ static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
+ if (enc->crtc_id) {
+ crtc = enc->crtc_id;
+ for (iter = modeset_list; iter; iter = iter->next) {
+- if (iter->crtc == crtc) {
++ if (iter->crtc == (uint32_t)crtc) {
+ crtc = -1;
+ break;
+ }
+@@ -389,7 +385,7 @@ static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
+ /* check that no other device already uses this CRTC */
+ crtc = res->crtcs[j];
+ for (iter = modeset_list; iter; iter = iter->next) {
+- if (iter->crtc == crtc) {
++ if (iter->crtc == (uint32_t)crtc) {
+ crtc = -1;
+ break;
+ }
+@@ -503,6 +499,12 @@ err_destroy:
+ return ret;
+ }
+
++static void psplash_drm_flip(PSplashCanvas *canvas, int sync)
++{
++ (void)canvas;
++ (void)sync;
++}
++
+ /*
+ * Finally! We have a connector with a suitable CRTC. We know which mode we want
+ * to use and we have a framebuffer of the correct size that we can write to.
+@@ -532,155 +534,89 @@ err_destroy:
+ * also often not guaranteed. So instead, we only use one connector per CRTC.
+ *
+ * Before calling drmModeSetCrtc() we also save the current CRTC configuration.
+- * This is used in modeset_cleanup() to restore the CRTC to the same mode as was
+- * before we changed it.
++ * This is used in psplash_drm_destroy() to restore the CRTC to the same mode as
++ * was before we changed it.
+ * If we don't do this, the screen will stay blank after we exit until another
+ * application performs modesetting itself.
+ */
+
+-int main(int argc, char **argv)
++PSplashDRM* psplash_drm_new(int angle, int dev_id)
+ {
+- int ret, fd;
+- const char *card;
++ PSplashDRM *drm = NULL;
++ int ret;
++ char card[] = "/dev/dri/card0";
+ struct modeset_dev *iter;
+
+- /* check which DRM device to open */
+- if (argc > 1)
+- card = argv[1];
+- else
+- card = "/dev/dri/card0";
++ if ((drm = malloc(sizeof(*drm))) == NULL) {
++ perror("malloc");
++ goto error;
++ }
++ drm->canvas.priv = drm;
++ drm->canvas.flip = psplash_drm_flip;
++
++ if (dev_id > 0 && dev_id < 10) {
++ // Conversion from integer to ascii.
++ card[13] = dev_id + 48;
++ }
+
+ fprintf(stderr, "using card '%s'\n", card);
+
+ /* open the DRM device */
+- ret = modeset_open(&fd, card);
++ ret = modeset_open(&drm->fd, card);
+ if (ret)
+- goto out_return;
++ goto error;
+
+ /* prepare all connectors and CRTCs */
+- ret = modeset_prepare(fd);
++ ret = modeset_prepare(drm->fd);
+ if (ret)
+- goto out_close;
++ goto error;
+
+ /* perform actual modesetting on each found connector+CRTC */
+ for (iter = modeset_list; iter; iter = iter->next) {
+- iter->saved_crtc = drmModeGetCrtc(fd, iter->crtc);
+- ret = drmModeSetCrtc(fd, iter->crtc, iter->fb, 0, 0,
++ iter->saved_crtc = drmModeGetCrtc(drm->fd, iter->crtc);
++ ret = drmModeSetCrtc(drm->fd, iter->crtc, iter->fb, 0, 0,
+ &iter->conn, 1, &iter->mode);
+ if (ret)
+ fprintf(stderr, "cannot set CRTC for connector %u (%d): %m\n",
+ iter->conn, errno);
+ }
+
+- /* draw some colors for 5seconds */
+- modeset_draw();
+-
+- /* cleanup everything */
+- modeset_cleanup(fd);
+-
+- ret = 0;
+-
+-out_close:
+- close(fd);
+-out_return:
+- if (ret) {
+- errno = -ret;
+- fprintf(stderr, "modeset failed with error %d: %m\n", errno);
+- } else {
+- fprintf(stderr, "exiting\n");
+- }
+- return ret;
++ drm->canvas.data = modeset_list->map;
++ drm->canvas.width = modeset_list->width;
++ drm->canvas.height = modeset_list->height;
++ drm->canvas.bpp = 32;
++ drm->canvas.stride = modeset_list->stride;
++ drm->canvas.angle = angle;
++ drm->canvas.rgbmode = RGB888;
++
++ return drm;
++error:
++ psplash_drm_destroy(drm);
++ return NULL;
+ }
+
+ /*
+- * A short helper function to compute a changing color value. No need to
+- * understand it.
+- */
+-
+-static uint8_t next_color(bool *up, uint8_t cur, unsigned int mod)
+-{
+- uint8_t next;
+-
+- next = cur + (*up ? 1 : -1) * (rand() % mod);
+- if ((*up && next < cur) || (!*up && next > cur)) {
+- *up = !*up;
+- next = cur;
+- }
+-
+- return next;
+-}
+-
+-/*
+- * modeset_draw(): This draws a solid color into all configured framebuffers.
+- * Every 100ms the color changes to a slightly different color so we get some
+- * kind of smoothly changing color-gradient.
+- *
+- * The color calculation can be ignored as it is pretty boring. So the
+- * interesting stuff is iterating over "modeset_list" and then through all lines
+- * and width. We then set each pixel individually to the current color.
+- *
+- * We do this 50 times as we sleep 100ms after each redraw round. This makes
+- * 50*100ms = 5000ms = 5s so it takes about 5seconds to finish this loop.
+- *
+- * Please note that we draw directly into the framebuffer. This means that you
+- * will see flickering as the monitor might refresh while we redraw the screen.
+- * To avoid this you would need to use two framebuffers and a call to
+- * drmModeSetCrtc() to switch between both buffers.
+- * You can also use drmModePageFlip() to do a vsync'ed pageflip. But this is
+- * beyond the scope of this document.
+- */
+-
+-static void modeset_draw(void)
+-{
+- uint8_t r, g, b;
+- bool r_up, g_up, b_up;
+- unsigned int i, j, k, off;
+- struct modeset_dev *iter;
+-
+- srand(time(NULL));
+- r = rand() % 0xff;
+- g = rand() % 0xff;
+- b = rand() % 0xff;
+- r_up = g_up = b_up = true;
+-
+- for (i = 0; i < 50; ++i) {
+- r = next_color(&r_up, r, 20);
+- g = next_color(&g_up, g, 10);
+- b = next_color(&b_up, b, 5);
+-
+- for (iter = modeset_list; iter; iter = iter->next) {
+- for (j = 0; j < iter->height; ++j) {
+- for (k = 0; k < iter->width; ++k) {
+- off = iter->stride * j + k * 4;
+- *(uint32_t*)&iter->map[off] =
+- (r << 16) | (g << 8) | b;
+- }
+- }
+- }
+-
+- usleep(100000);
+- }
+-}
+-
+-/*
+- * modeset_cleanup(fd): This cleans up all the devices we created during
++ * psplash_drm_destroy(drm): This cleans up all the devices we created during
+ * modeset_prepare(). It resets the CRTCs to their saved states and deallocates
+ * all memory.
+ * It should be pretty obvious how all of this works.
+ */
+
+-static void modeset_cleanup(int fd)
++void psplash_drm_destroy(PSplashDRM *drm)
+ {
+ struct modeset_dev *iter;
+ struct drm_mode_destroy_dumb dreq;
+
++ if (!drm)
++ return;
++
+ while (modeset_list) {
+ /* remove from global list */
+ iter = modeset_list;
+ modeset_list = iter->next;
+
+ /* restore saved CRTC configuration */
+- drmModeSetCrtc(fd,
++ drmModeSetCrtc(drm->fd,
+ iter->saved_crtc->crtc_id,
+ iter->saved_crtc->buffer_id,
+ iter->saved_crtc->x,
+@@ -694,16 +630,19 @@ static void modeset_cleanup(int fd)
+ munmap(iter->map, iter->size);
+
+ /* delete framebuffer */
+- drmModeRmFB(fd, iter->fb);
++ drmModeRmFB(drm->fd, iter->fb);
+
+ /* delete dumb buffer */
+ memset(&dreq, 0, sizeof(dreq));
+ dreq.handle = iter->handle;
+- drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
++ drmIoctl(drm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
+
+ /* free allocated memory */
+ free(iter);
+ }
++
++ close(drm->fd);
++ free(drm);
+ }
+
+ /*
+diff --git a/psplash-drm.h b/psplash-drm.h
+new file mode 100644
+index 0000000..e987fd6
+--- /dev/null
++++ b/psplash-drm.h
+@@ -0,0 +1,17 @@
++#ifndef _HAVE_PSPLASH_DRM_H
++#define _HAVE_PSPLASH_DRM_H
++
++#include "psplash-draw.h"
++
++typedef struct PSplashDRM
++{
++ PSplashCanvas canvas;
++ int fd;
++}
++PSplashDRM;
++
++void psplash_drm_destroy(PSplashDRM *drm);
++
++PSplashDRM* psplash_drm_new(int angle, int dev_id);
++
++#endif
+diff --git a/psplash.c b/psplash.c
+index 036dfb1..ebf8d7a 100644
+--- a/psplash.c
++++ b/psplash.c
+@@ -12,6 +12,9 @@
+
+ #include "psplash.h"
+ #include "psplash-fb.h"
++#ifdef ENABLE_DRM
++#include "psplash-drm.h"
++#endif
+ #include "psplash-config.h"
+ #include "psplash-colors.h"
+ #include "psplash-poky-img.h"
+@@ -224,8 +227,11 @@ int
+ main (int argc, char** argv)
+ {
+ char *rundir;
+- int pipe_fd, i = 0, angle = 0, fbdev_id = 0, ret = 0;
+- PSplashFB *fb;
++ int pipe_fd, i = 0, angle = 0, dev_id = 0, use_drm = 0, ret = 0;
++ PSplashFB *fb = NULL;
++#ifdef ENABLE_DRM
++ PSplashDRM *drm = NULL;
++#endif
+ PSplashCanvas *canvas;
+ bool disable_console_switch = FALSE;
+
+@@ -247,16 +253,24 @@ main (int argc, char** argv)
+ continue;
+ }
+
+- if (!strcmp(argv[i],"-f") || !strcmp(argv[i],"--fbdev"))
++ if (!strcmp(argv[i], "-f") || !strcmp(argv[i], "--fbdev") ||
++ !strcmp(argv[i], "-d") || !strcmp(argv[i], "--dev"))
+ {
+ if (++i >= argc) goto fail;
+- fbdev_id = atoi(argv[i]);
++ dev_id = atoi(argv[i]);
+ continue;
+ }
+
++#ifdef ENABLE_DRM
++ if (!strcmp(argv[i], "--drm")) {
++ use_drm = 1;
++ continue;
++ }
++#endif
++
+ fail:
+ fprintf(stderr,
+- "Usage: %s [-n|--no-console-switch][-a|--angle <0|90|180|270>][-f|--fbdev <0..9>]\n",
++ "Usage: %s [-n|--no-console-switch][-a|--angle <0|90|180|270>][-f|--fbdev|-d|--dev <0..9>][--drm]\n",
+ argv[0]);
+ exit(-1);
+ }
+@@ -291,12 +305,21 @@ main (int argc, char** argv)
+ if (!disable_console_switch)
+ psplash_console_switch ();
+
+- if ((fb = psplash_fb_new(angle,fbdev_id)) == NULL)
+- {
+- ret = -1;
+- goto fb_fail;
++ if (use_drm) {
++#ifdef ENABLE_DRM
++ if ((drm = psplash_drm_new(angle, dev_id)) == NULL) {
++ ret = -1;
++ goto error;
++ }
++ canvas = &drm->canvas;
++#endif
++ } else {
++ if ((fb = psplash_fb_new(angle, dev_id)) == NULL) {
++ ret = -1;
++ goto error;
+ }
+- canvas = &fb->canvas;
++ canvas = &fb->canvas;
++ }
+
+ #ifdef HAVE_SYSTEMD
+ sd_notify(0, "READY=1");
+@@ -349,9 +372,14 @@ main (int argc, char** argv)
+
+ psplash_main(canvas, pipe_fd, 0);
+
+- psplash_fb_destroy (fb);
++ if (fb)
++ psplash_fb_destroy(fb);
++#ifdef ENABLE_DRM
++ if (drm)
++ psplash_drm_destroy(drm);
++#endif
+
+- fb_fail:
++ error:
+ unlink(PSPLASH_FIFO);
+
+ if (!disable_console_switch)
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0013-Reverse-modeset_list.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0013-Reverse-modeset_list.patch
new file mode 100644
index 00000000..e1e171fc
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0013-Reverse-modeset_list.patch
@@ -0,0 +1,48 @@
+From 6a73289e30a8b60c65f49ac477e35fd3302bafe0 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:52 +0300
+Subject: [PATCH 13/17] Reverse modeset_list
+
+Now, it has the same order as connectors in drmModeGetResources. As
+result splash screen will be drawn on the first connector.
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ psplash-drm.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/psplash-drm.c b/psplash-drm.c
+index 30850ed..2468cf1 100644
+--- a/psplash-drm.c
++++ b/psplash-drm.c
+@@ -185,7 +185,7 @@ static int modeset_prepare(int fd)
+ drmModeRes *res;
+ drmModeConnector *conn;
+ int i;
+- struct modeset_dev *dev;
++ struct modeset_dev *dev, *last_dev = NULL;
+ int ret;
+
+ /* retrieve resources */
+@@ -226,8 +226,13 @@ static int modeset_prepare(int fd)
+
+ /* free connector data and link device into global list */
+ drmModeFreeConnector(conn);
+- dev->next = modeset_list;
+- modeset_list = dev;
++ if (last_dev == NULL) {
++ modeset_list = dev;
++ last_dev = dev;
++ } else {
++ last_dev->next = dev;
++ last_dev = dev;
++ }
+ }
+
+ /* free resources again */
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0014-psplash-drm.c-Allocate-resources-only-for-the-first-.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0014-psplash-drm.c-Allocate-resources-only-for-the-first-.patch
new file mode 100644
index 00000000..28b1014b
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0014-psplash-drm.c-Allocate-resources-only-for-the-first-.patch
@@ -0,0 +1,46 @@
+From 7423f166c8899b84448f68739d5293f19f8dfd06 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:53 +0300
+Subject: [PATCH 14/17] psplash-drm.c: Allocate resources only for the first
+ connector
+
+Since splash screen is shown only on the first scanout, there is no need
+to allocate resources for next connectors.
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ psplash-drm.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/psplash-drm.c b/psplash-drm.c
+index 2468cf1..5e56286 100644
+--- a/psplash-drm.c
++++ b/psplash-drm.c
+@@ -39,6 +39,8 @@
+ #include <xf86drmMode.h>
+ #include "psplash-drm.h"
+
++#define MIN(a,b) ((a) < (b) ? (a) : (b))
++
+ struct modeset_dev;
+ static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
+ struct modeset_dev *dev);
+@@ -196,8 +198,10 @@ static int modeset_prepare(int fd)
+ return -errno;
+ }
+
+- /* iterate all connectors */
+- for (i = 0; i < res->count_connectors; ++i) {
++ /* ~iterate all connectors~ - Use first connector if present. It is
++ optimization related workaround since psplash supports drawing splash
++ screen on one scanout anyway. */
++ for (i = 0; i < MIN(res->count_connectors, 1); ++i) {
+ /* get information for each connector */
+ conn = drmModeGetConnector(fd, res->connectors[i]);
+ if (!conn) {
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch
new file mode 100644
index 00000000..cd65c990
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch
@@ -0,0 +1,350 @@
+From 266b4808094ae636a64e545f5e59fb612827e0ee Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:54 +0300
+Subject: [PATCH 15/17] psplash-drm.c: Implement double buffering
+
+Based on
+https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset-double-buffered.c
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ psplash-drm.c | 176 +++++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 140 insertions(+), 36 deletions(-)
+
+diff --git a/psplash-drm.c b/psplash-drm.c
+index 5e56286..fcb7507 100644
+--- a/psplash-drm.c
++++ b/psplash-drm.c
+@@ -29,6 +29,7 @@
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <stdint.h>
++#include <inttypes.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -41,10 +42,12 @@
+
+ #define MIN(a,b) ((a) < (b) ? (a) : (b))
+
++struct modeset_buf;
+ struct modeset_dev;
+ static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
+ struct modeset_dev *dev);
+-static int modeset_create_fb(int fd, struct modeset_dev *dev);
++static int modeset_create_fb(int fd, struct modeset_buf *buf);
++static void modeset_destroy_fb(int fd, struct modeset_buf *buf);
+ static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
+ struct modeset_dev *dev);
+ static int modeset_open(int *out, const char *node);
+@@ -144,18 +147,45 @@ static int modeset_open(int *out, const char *node)
+ * }
+ */
+
+-struct modeset_dev {
+- struct modeset_dev *next;
++/*
++ * Previously, we used the modeset_dev objects to hold buffer informations, too.
++ * Technically, we could have split them but avoided this to make the
++ * example simpler.
++ * However, in this example we need 2 buffers. One back buffer and one front
++ * buffer. So we introduce a new structure modeset_buf which contains everything
++ * related to a single buffer. Each device now gets an array of two of these
++ * buffers.
++ * Each buffer consists of width, height, stride, size, handle, map and fb-id.
++ * They have the same meaning as before.
++ *
++ * Each device also gets a new integer field: front_buf. This field contains the
++ * index of the buffer that is currently used as front buffer / scanout buffer.
++ * In our example it can be 0 or 1. We flip it by using XOR:
++ * dev->front_buf ^= dev->front_buf
++ *
++ * Everything else stays the same.
++ */
+
++struct modeset_buf {
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ uint32_t size;
+ uint32_t handle;
+ void *map;
++ uint32_t fb;
++};
++
++struct modeset_dev {
++ struct modeset_dev *next;
++
++ uint32_t width;
++ uint32_t height;
++
++ unsigned int front_buf;
++ struct modeset_buf bufs[2];
+
+ drmModeModeInfo mode;
+- uint32_t fb;
+ uint32_t conn;
+ uint32_t crtc;
+ drmModeCrtc *saved_crtc;
+@@ -292,10 +322,15 @@ static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
+ return -EFAULT;
+ }
+
+- /* copy the mode information into our device structure */
++ /* copy the mode information into our device structure and into both
++ * buffers */
+ memcpy(&dev->mode, &conn->modes[0], sizeof(dev->mode));
+ dev->width = conn->modes[0].hdisplay;
+ dev->height = conn->modes[0].vdisplay;
++ dev->bufs[0].width = dev->width;
++ dev->bufs[0].height = dev->height;
++ dev->bufs[1].width = dev->width;
++ dev->bufs[1].height = dev->height;
+ fprintf(stderr, "mode for connector %u is %ux%u\n",
+ conn->connector_id, dev->width, dev->height);
+
+@@ -307,14 +342,30 @@ static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
+ return ret;
+ }
+
+- /* create a framebuffer for this CRTC */
+- ret = modeset_create_fb(fd, dev);
++ /* create framebuffer #1 for this CRTC */
++ ret = modeset_create_fb(fd, &dev->bufs[0]);
+ if (ret) {
+ fprintf(stderr, "cannot create framebuffer for connector %u\n",
+ conn->connector_id);
+ return ret;
+ }
+
++ /* create framebuffer #2 for this CRTC */
++ ret = modeset_create_fb(fd, &dev->bufs[1]);
++ if (ret) {
++ fprintf(stderr, "cannot create framebuffer for connector %u\n",
++ conn->connector_id);
++ modeset_destroy_fb(fd, &dev->bufs[0]);
++ return ret;
++ }
++
++ if (dev->bufs[0].size != dev->bufs[1].size) {
++ fprintf(stderr, "front buffer size %" PRIu32 " does not match "
++ "back buffer size %" PRIu32 "\n",
++ dev->bufs[0].size, dev->bufs[1].size);
++ return -1;
++ }
++
+ return 0;
+ }
+
+@@ -441,7 +492,7 @@ static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
+ * memory directly via the dev->map memory map.
+ */
+
+-static int modeset_create_fb(int fd, struct modeset_dev *dev)
++static int modeset_create_fb(int fd, struct modeset_buf *buf)
+ {
+ struct drm_mode_create_dumb creq;
+ struct drm_mode_destroy_dumb dreq;
+@@ -450,8 +501,8 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev)
+
+ /* create dumb buffer */
+ memset(&creq, 0, sizeof(creq));
+- creq.width = dev->width;
+- creq.height = dev->height;
++ creq.width = buf->width;
++ creq.height = buf->height;
+ creq.bpp = 32;
+ ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
+ if (ret < 0) {
+@@ -459,13 +510,13 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev)
+ errno);
+ return -errno;
+ }
+- dev->stride = creq.pitch;
+- dev->size = creq.size;
+- dev->handle = creq.handle;
++ buf->stride = creq.pitch;
++ buf->size = creq.size;
++ buf->handle = creq.handle;
+
+ /* create framebuffer object for the dumb-buffer */
+- ret = drmModeAddFB(fd, dev->width, dev->height, 24, 32, dev->stride,
+- dev->handle, &dev->fb);
++ ret = drmModeAddFB(fd, buf->width, buf->height, 24, 32, buf->stride,
++ buf->handle, &buf->fb);
+ if (ret) {
+ fprintf(stderr, "cannot create framebuffer (%d): %m\n",
+ errno);
+@@ -475,7 +526,7 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev)
+
+ /* prepare buffer for memory mapping */
+ memset(&mreq, 0, sizeof(mreq));
+- mreq.handle = dev->handle;
++ mreq.handle = buf->handle;
+ ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
+ if (ret) {
+ fprintf(stderr, "cannot map dumb buffer (%d): %m\n",
+@@ -485,9 +536,9 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev)
+ }
+
+ /* perform actual memory mapping */
+- dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED,
++ buf->map = mmap(0, buf->size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, mreq.offset);
+- if (dev->map == MAP_FAILED) {
++ if (buf->map == MAP_FAILED) {
+ fprintf(stderr, "cannot mmap dumb buffer (%d): %m\n",
+ errno);
+ ret = -errno;
+@@ -495,23 +546,73 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev)
+ }
+
+ /* clear the framebuffer to 0 */
+- memset(dev->map, 0, dev->size);
++ memset(buf->map, 0, buf->size);
+
+ return 0;
+
+ err_fb:
+- drmModeRmFB(fd, dev->fb);
++ drmModeRmFB(fd, buf->fb);
+ err_destroy:
+ memset(&dreq, 0, sizeof(dreq));
+- dreq.handle = dev->handle;
++ dreq.handle = buf->handle;
+ drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
+ return ret;
+ }
+
++/*
++ * modeset_destroy_fb() is a new function. It does exactly the reverse of
++ * modeset_create_fb() and destroys a single framebuffer. The modeset.c example
++ * used to do this directly in modeset_cleanup().
++ * We simply unmap the buffer, remove the drm-FB and destroy the memory buffer.
++ */
++
++static void modeset_destroy_fb(int fd, struct modeset_buf *buf)
++{
++ struct drm_mode_destroy_dumb dreq;
++
++ /* unmap buffer */
++ munmap(buf->map, buf->size);
++
++ /* delete framebuffer */
++ drmModeRmFB(fd, buf->fb);
++
++ /* delete dumb buffer */
++ memset(&dreq, 0, sizeof(dreq));
++ dreq.handle = buf->handle;
++ drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
++}
++
+ static void psplash_drm_flip(PSplashCanvas *canvas, int sync)
+ {
+- (void)canvas;
++ PSplashDRM *drm = canvas->priv;
++ struct modeset_buf *buf;
++ int ret;
++
+ (void)sync;
++
++ /* pick a back buffer */
++ buf = &modeset_list->bufs[modeset_list->front_buf ^ 1];
++
++ /* set back buffer as a front buffer */
++ ret = drmModeSetCrtc(drm->fd, modeset_list->crtc, buf->fb, 0, 0,
++ &modeset_list->conn, 1, &modeset_list->mode);
++ if (ret) {
++ fprintf(stderr, "cannot flip CRTC for connector %u (%d): %m\n",
++ modeset_list->conn, errno);
++ return;
++ }
++
++ /* update front buffer index */
++ modeset_list->front_buf ^= 1;
++
++ /* update back buffer pointer */
++ drm->canvas.data = modeset_list->bufs[modeset_list->front_buf ^ 1].map;
++
++ /* Sync new front to new back when requested */
++ if (sync)
++ memcpy(modeset_list->bufs[modeset_list->front_buf ^ 1].map,
++ modeset_list->bufs[modeset_list->front_buf].map,
++ modeset_list->bufs[0].size);
+ }
+
+ /*
+@@ -555,6 +656,7 @@ PSplashDRM* psplash_drm_new(int angle, int dev_id)
+ int ret;
+ char card[] = "/dev/dri/card0";
+ struct modeset_dev *iter;
++ struct modeset_buf *buf;
+
+ if ((drm = malloc(sizeof(*drm))) == NULL) {
+ perror("malloc");
+@@ -583,18 +685,28 @@ PSplashDRM* psplash_drm_new(int angle, int dev_id)
+ /* perform actual modesetting on each found connector+CRTC */
+ for (iter = modeset_list; iter; iter = iter->next) {
+ iter->saved_crtc = drmModeGetCrtc(drm->fd, iter->crtc);
+- ret = drmModeSetCrtc(drm->fd, iter->crtc, iter->fb, 0, 0,
++ buf = &iter->bufs[iter->front_buf];
++ ret = drmModeSetCrtc(drm->fd, iter->crtc, buf->fb, 0, 0,
+ &iter->conn, 1, &iter->mode);
+ if (ret)
+ fprintf(stderr, "cannot set CRTC for connector %u (%d): %m\n",
+ iter->conn, errno);
+ }
+
+- drm->canvas.data = modeset_list->map;
++ drm->canvas.data = modeset_list->bufs[modeset_list->front_buf ^ 1].map;
+ drm->canvas.width = modeset_list->width;
+ drm->canvas.height = modeset_list->height;
+ drm->canvas.bpp = 32;
+- drm->canvas.stride = modeset_list->stride;
++
++ if (modeset_list->bufs[0].stride != modeset_list->bufs[1].stride) {
++ fprintf(stderr, "front buffer stride %" PRIu32 " does not match"
++ " back buffer stride %" PRIu32 "\n",
++ modeset_list->bufs[0].stride,
++ modeset_list->bufs[1].stride);
++ goto error;
++ }
++ drm->canvas.stride = modeset_list->bufs[0].stride;
++
+ drm->canvas.angle = angle;
+ drm->canvas.rgbmode = RGB888;
+
+@@ -614,7 +726,6 @@ error:
+ void psplash_drm_destroy(PSplashDRM *drm)
+ {
+ struct modeset_dev *iter;
+- struct drm_mode_destroy_dumb dreq;
+
+ if (!drm)
+ return;
+@@ -635,16 +746,9 @@ void psplash_drm_destroy(PSplashDRM *drm)
+ &iter->saved_crtc->mode);
+ drmModeFreeCrtc(iter->saved_crtc);
+
+- /* unmap buffer */
+- munmap(iter->map, iter->size);
+-
+- /* delete framebuffer */
+- drmModeRmFB(drm->fd, iter->fb);
+-
+- /* delete dumb buffer */
+- memset(&dreq, 0, sizeof(dreq));
+- dreq.handle = iter->handle;
+- drmIoctl(drm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
++ /* destroy framebuffers */
++ modeset_destroy_fb(drm->fd, &iter->bufs[1]);
++ modeset_destroy_fb(drm->fd, &iter->bufs[0]);
+
+ /* free allocated memory */
+ free(iter);
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0016-Imprement-drm-lease-support.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0016-Imprement-drm-lease-support.patch
new file mode 100644
index 00000000..6a4bf387
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0016-Imprement-drm-lease-support.patch
@@ -0,0 +1,189 @@
+From 0fcca6600c7d74ec13986d3e9e795f4a7c8afe59 Mon Sep 17 00:00:00 2001
+From: Hiroyuki Ishii <ishii.hiroyuki002@jp.panasonic.com>
+Date: Tue, 27 Dec 2022 16:43:46 +0900
+Subject: [PATCH 16/17] Imprement drm-lease support
+
+Basic support to utilize drm-lease device via drm-lease-manager.
+
+Known issue:
+- --angle option does not work correctly with drm-lease enabled
+
+Signed-off-by: Hiroyuki Ishii <ishii.hiroyuki002@jp.panasonic.com>
+---
+ Makefile.am | 5 +++++
+ configure.ac | 9 +++++++++
+ psplash-drm-lease.h | 10 ++++++++++
+ psplash-drm.c | 44 +++++++++++++++++++++++++++++++++++++++-----
+ psplash.c | 12 ++++++++++++
+ 5 files changed, 75 insertions(+), 5 deletions(-)
+ create mode 100644 psplash-drm-lease.h
+
+diff --git a/Makefile.am b/Makefile.am
+index c3d4f03..3657889 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -19,6 +19,11 @@ psplash_CPPFLAGS += $(LIBDRM_CFLAGS) -DENABLE_DRM
+ psplash_LDFLAGS += $(LIBDRM_LIBS)
+ endif
+
++if ENABLE_DRM_LEASE
++psplash_CPPFLAGS += $(LIBDRM_LEASE_CFLAGS) -DENABLE_DRM_LEASE
++psplash_LDFLAGS += $(LIBDRM_LEASE_LIBS)
++endif
++
+ if HAVE_SYSTEMD
+ psplash_CPPFLAGS += $(SYSTEMD_CFLAGS) -DHAVE_SYSTEMD
+ psplash_LDFLAGS += $(SYSTEMD_LIBS)
+diff --git a/configure.ac b/configure.ac
+index 2e5c4f5..1a752e3 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -21,6 +21,15 @@ AS_IF([test "x$enable_drm" = "xyes"], [
+
+ AM_CONDITIONAL([ENABLE_DRM], [test "x$enable_drm" = "xyes"])
+
++AC_ARG_ENABLE(drm-lease,
++ AS_HELP_STRING([--enable-drm-lease], [enable drm-lease (default is 'no')]))
++
++AS_IF([test "x$enable_drm_lease" = "xyes"], [
++ PKG_CHECK_MODULES(LIBDRM_LEASE, libdlmclient)
++])
++
++AM_CONDITIONAL([ENABLE_DRM_LEASE], [test "x$enable_drm_lease" = "xyes"])
++
+ AC_ARG_WITH([systemd], AS_HELP_STRING([--with-systemd], [Build with systemd
+ support]))
+
+diff --git a/psplash-drm-lease.h b/psplash-drm-lease.h
+new file mode 100644
+index 0000000..46289c3
+--- /dev/null
++++ b/psplash-drm-lease.h
+@@ -0,0 +1,10 @@
++#ifndef _HAVE_PSPLASH_DRM_LEASE_H
++#define _HAVE_PSPLASH_DRM_LEASE_H
++#ifdef ENABLE_DRM_LEASE
++
++#include <dlmclient.h>
++
++void drm_set_lease_name(char *);
++
++#endif // ENABLE_DRM_LEASE
++#endif // _HAVE_PSPLASH_DRM_LEASE_H
+diff --git a/psplash-drm.c b/psplash-drm.c
+index fcb7507..a5aff90 100644
+--- a/psplash-drm.c
++++ b/psplash-drm.c
+@@ -39,6 +39,9 @@
+ #include <xf86drm.h>
+ #include <xf86drmMode.h>
+ #include "psplash-drm.h"
++#ifdef ENABLE_DRM_LEASE
++#include "psplash-drm-lease.h"
++#endif
+
+ #define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+@@ -53,6 +56,10 @@ static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
+ static int modeset_open(int *out, const char *node);
+ static int modeset_prepare(int fd);
+
++#ifdef ENABLE_DRM_LEASE
++char *drm_lease_name;
++#endif
++
+ /*
+ * When the linux kernel detects a graphics-card on your machine, it loads the
+ * correct device driver (located in kernel-tree at ./drivers/gpu/drm/<xy>) and
+@@ -662,6 +669,7 @@ PSplashDRM* psplash_drm_new(int angle, int dev_id)
+ perror("malloc");
+ goto error;
+ }
++ drm->fd = 0;
+ drm->canvas.priv = drm;
+ drm->canvas.flip = psplash_drm_flip;
+
+@@ -670,12 +678,30 @@ PSplashDRM* psplash_drm_new(int angle, int dev_id)
+ card[13] = dev_id + 48;
+ }
+
+- fprintf(stderr, "using card '%s'\n", card);
++#ifdef ENABLE_DRM_LEASE
++ if (drm_lease_name) {
++ fprintf(stderr, "using drm lease '%s'\n", drm_lease_name);
++ struct dlm_lease *lease = dlm_get_lease(drm_lease_name);
++ if (lease) {
++ drm->fd = dlm_lease_fd(lease);
++ if (!drm->fd)
++ dlm_release_lease(lease);
++ }
++ if (!drm->fd) {
++ fprintf(stderr, "Could not get DRM lease %s\n", drm_lease_name);
++ goto error;
++ }
++ }
++#endif
+
+- /* open the DRM device */
+- ret = modeset_open(&drm->fd, card);
+- if (ret)
+- goto error;
++ if (!drm->fd) {
++ fprintf(stderr, "using card '%s'\n", card);
++
++ /* open the DRM device */
++ ret = modeset_open(&drm->fd, card);
++ if (ret)
++ goto error;
++ }
+
+ /* prepare all connectors and CRTCs */
+ ret = modeset_prepare(drm->fd);
+@@ -758,6 +784,14 @@ void psplash_drm_destroy(PSplashDRM *drm)
+ free(drm);
+ }
+
++#ifdef ENABLE_DRM_LEASE
++void drm_set_lease_name (char *name) {
++ if (!name)
++ return;
++ drm_lease_name = strdup(name);
++}
++#endif
++
+ /*
+ * I hope this was a short but easy overview of the DRM modesetting API. The DRM
+ * API offers much more capabilities including:
+diff --git a/psplash.c b/psplash.c
+index ebf8d7a..4aa650d 100644
+--- a/psplash.c
++++ b/psplash.c
+@@ -15,6 +15,9 @@
+ #ifdef ENABLE_DRM
+ #include "psplash-drm.h"
+ #endif
++#ifdef ENABLE_DRM_LEASE
++#include "psplash-drm-lease.h"
++#endif
+ #include "psplash-config.h"
+ #include "psplash-colors.h"
+ #include "psplash-poky-img.h"
+@@ -267,6 +270,15 @@ main (int argc, char** argv)
+ continue;
+ }
+ #endif
++#ifdef ENABLE_DRM_LEASE
++ if (!strcmp(argv[i],"--drm-lease"))
++ {
++ if (++i >= argc) goto fail;
++ drm_set_lease_name(argv[i]);
++ use_drm = 1;
++ continue;
++ }
++#endif
+
+ fail:
+ fprintf(stderr,
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0017-drm-lease-Fix-incorrect-drawing-with-portrait-orient.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0017-drm-lease-Fix-incorrect-drawing-with-portrait-orient.patch
new file mode 100644
index 00000000..d68bc49d
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0017-drm-lease-Fix-incorrect-drawing-with-portrait-orient.patch
@@ -0,0 +1,42 @@
+From a4f7a5f0dd287895461cd007b23094459b6b88cb Mon Sep 17 00:00:00 2001
+From: Hiroyuki Ishii <ishii.hiroyuki002@jp.panasonic.com>
+Date: Wed, 28 Dec 2022 15:17:24 +0900
+Subject: [PATCH 17/17] drm-lease: Fix incorrect drawing with portrait
+ orientation
+
+Signed-off-by: Hiroyuki Ishii <ishii.hiroyuki002@jp.panasonic.com>
+---
+ psplash-drm.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/psplash-drm.c b/psplash-drm.c
+index a5aff90..c20df13 100644
+--- a/psplash-drm.c
++++ b/psplash-drm.c
+@@ -736,6 +736,23 @@ PSplashDRM* psplash_drm_new(int angle, int dev_id)
+ drm->canvas.angle = angle;
+ drm->canvas.rgbmode = RGB888;
+
++ /*
++ * There seems some difference about handling portrait angle between
++ * pure drm vs drm-lease. We'd use a method as same with psplash-fb
++ * for drm-lease devices.
++ */
++ if (drm_lease_name) {
++ switch (angle) {
++ case 270:
++ case 90:
++ drm->canvas.width = modeset_list->height;
++ drm->canvas.height = modeset_list->width;
++ break;
++ default:
++ break;
++ }
++ }
++
+ return drm;
+ error:
+ psplash_drm_destroy(drm);
+--
+2.25.1
+
diff --git a/meta-agl-drm-lease/recipes-core/psplash/psplash_git.bbappend b/meta-agl-drm-lease/recipes-core/psplash/psplash_git.bbappend
new file mode 100644
index 00000000..56650669
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/psplash_git.bbappend
@@ -0,0 +1,43 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+# drm-backend backport from:
+# https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+SRC_URI += " \
+ file://0001-Fix-duplicated-definition-of-bool.patch \
+ file://0002-Trim-trailing-spaces.patch \
+ file://0003-Fix-unused-result-warnings.patch \
+ file://0004-Remove-unused-save_termios.patch \
+ file://0005-Remove-psplash-fb.h-from-psplash.h.patch \
+ file://0006-Extract-plot-pixel-from-psplash-fb.patch \
+ file://0007-Extract-draw-rect-image-from-psplash-fb.patch \
+ file://0008-Extract-draw-font-from-psplash-fb.patch \
+ file://0009-psplash.c-Make-psplash_draw_-msg-progress-independen.patch \
+ file://0010-Rework-flip-as-function-pointer.patch \
+ file://0011-Import-drm-howto-modeset.c-as-psplash-drm.c.patch \
+ file://0012-Implement-drm-backend.patch \
+ file://0013-Reverse-modeset_list.patch \
+ file://0014-psplash-drm.c-Allocate-resources-only-for-the-first-.patch \
+ file://0015-psplash-drm.c-Implement-double-buffering.patch \
+ "
+
+# drm-lease support from:
+# https://github.com/agl-ic-eg/meta-agl-demo/tree/main/recipes-core/psplash
+SRC_URI += " \
+ file://0016-Imprement-drm-lease-support.patch \
+ file://0017-drm-lease-Fix-incorrect-drawing-with-portrait-orient.patch \
+ "
+
+# Licesnse checksum was changed by above patches
+LIC_FILES_CHKSUM = "file://psplash.h;beginline=1;endline=8;md5=db1ed16abf4be6de3d79201093ac4f07"
+
+PACKAGECONFIG[drm] = "--enable-drm,,libdrm"
+PSPLASH_ARGS += "${@bb.utils.contains('PACKAGECONFIG', 'drm', '--drm', '', d)}"
+
+PACKAGECONFIG[drm-lease] = "--enable-drm-lease,,drm-lease-manager"
+PSPLASH_DRM_LEASE_ARGS ??= "--drm-lease lease0"
+PSPLASH_ARGS += "${@bb.utils.contains('PACKAGECONFIG', 'drm-lease', '${PSPLASH_DRM_LEASE_ARGS}', '', d)}"
+RDEPENDS:${PN} += "${@bb.utils.contains('PACKAGECONFIG', 'drm-lease', 'drm-lease-manager', '', d)}"
+
+do_install:append () {
+ sed -i -e "s!^\(ExecStart=/usr/bin/psplash.*\)!\1 ${PSPLASH_ARGS}!" ${D}${systemd_system_unitdir}/psplash-start.service
+}