Skip to content

Instantly share code, notes, and snippets.

@VinDuv
Created January 23, 2021 17:37
Show Gist options
  • Save VinDuv/ccfa293f8a665512fc3e87ab05902bee to your computer and use it in GitHub Desktop.
Save VinDuv/ccfa293f8a665512fc3e87ab05902bee to your computer and use it in GitHub Desktop.
Display the boot logo at a smaller size for low-power CPUs
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 8268bbee8..708c1846e 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -45,6 +45,8 @@
#define FBPIXMAPSIZE (1024 * 8)
+#define RESIZE_RATIO 75
+
static DEFINE_MUTEX(registration_lock);
struct fb_info *registered_fb[FB_MAX] __read_mostly;
@@ -416,6 +418,36 @@ static void fb_rotate_logo(struct fb_info *info, u8 *dst,
image->data = dst;
}
+#ifdef CONFIG_LOGO_SMALL
+static char* fb_resize_logo(struct fb_image *target, const struct fb_image *source) {
+ char* resized_data;
+
+ target->dx = 0;
+ target->dy = 0;
+ target->width = source->width * RESIZE_RATIO / 100;
+ target->height = source->height * RESIZE_RATIO / 100;
+ target->fg_color = source->fg_color;
+ target->bg_color = source->bg_color;
+ resized_data = kmalloc_array(target->width, target->height, GFP_KERNEL);
+ target->data = resized_data;
+ target->cmap = source->cmap;
+
+ if (resized_data) {
+ int x, y;
+
+ for (x = 0 ; x < target->width ; x++) {
+ for (y = 0 ; y < target->height ; y++) {
+ int target_x = x * 100 / RESIZE_RATIO;
+ int target_y = y * 100 / RESIZE_RATIO;
+ resized_data[x + y * target->width] = source->data[target_x + target_y * source->width];
+ }
+ }
+ }
+
+ return resized_data;
+}
+#endif
+
static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
int rotate, unsigned int num)
{
@@ -457,11 +489,16 @@ static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
static int fb_show_logo_line(struct fb_info *info, int rotate,
const struct linux_logo *logo, int y,
- unsigned int n)
+ unsigned int n, unsigned int n_small
+)
{
u32 *palette = NULL, *saved_pseudo_palette = NULL;
unsigned char *logo_new = NULL, *logo_rotate = NULL;
struct fb_image image;
+ #ifdef CONFIG_LOGO_SMALL
+ struct fb_image small_image;
+ unsigned char *small_logo_data = NULL, *small_logo_rotate = NULL;
+ #endif
/* Return if the frame buffer is not mapped or suspended */
if (logo == NULL || info->state != FBINFO_STATE_RUNNING ||
@@ -502,6 +539,13 @@ static int fb_show_logo_line(struct fb_info *info, int rotate,
fb_set_logo(info, logo, logo_new, fb_logo.depth);
}
+ image.width = logo->width;
+ image.height = logo->height;
+
+ #ifdef CONFIG_LOGO_SMALL
+ small_logo_data = fb_resize_logo(&small_image, &image);
+ #endif
+
if (fb_center_logo) {
int xres = info->var.xres;
int yres = info->var.yres;
@@ -513,30 +557,59 @@ static int fb_show_logo_line(struct fb_info *info, int rotate,
while (n && (n * (logo->width + 8) - 8 > xres))
--n;
- image.dx = (xres - n * (logo->width + 8) - 8) / 2;
+
+ // Remaining empty space around the logo
+ xres = xres - n * (logo->width + 8) - 8;
+
+ #ifdef CONFIG_LOGO_SMALL
+ while (n_small && (n_small * (small_image.width + 8) - 8 > xres))
+ --n_small;
+
+ xres = xres - n_small * (small_image.width + 8) - 8;
+ #endif
+
+ image.dx = xres / 2;
image.dy = y ?: (yres - logo->height) / 2;
} else {
image.dx = 0;
image.dy = y;
}
- image.width = logo->width;
- image.height = logo->height;
+ #ifdef CONFIG_LOGO_SMALL
+ small_image.dx = image.dx + n * (logo->width + 8);
+ small_image.dy = image.dy + (logo->height - small_image.height);
+ #endif
if (rotate) {
logo_rotate = kmalloc_array(logo->width, logo->height,
GFP_KERNEL);
- if (logo_rotate)
+ if (logo_rotate) {
fb_rotate_logo(info, logo_rotate, &image, rotate);
+ }
+
+ #ifdef CONFIG_LOGO_SMALL
+ small_logo_rotate = kmalloc_array(small_image.width, small_image.height,
+ GFP_KERNEL);
+ if (small_logo_rotate) {
+ fb_rotate_logo(info, small_logo_rotate, &small_image, rotate);
+ }
+ #endif
}
fb_do_show_logo(info, &image, rotate, n);
+ #ifdef CONFIG_LOGO_SMALL
+ fb_do_show_logo(info, &small_image, rotate, n_small);
+ #endif
kfree(palette);
if (saved_pseudo_palette != NULL)
info->pseudo_palette = saved_pseudo_palette;
kfree(logo_new);
kfree(logo_rotate);
+ #ifdef CONFIG_LOGO_SMALL
+ kfree(small_logo_data);
+ kfree(small_logo_rotate);
+ #endif
return image.dy + logo->height;
}
@@ -590,7 +663,8 @@ static int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
for (i = 0; i < fb_logo_ex_num; i++)
y = fb_show_logo_line(info, rotate,
- fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
+ fb_logo_ex[i].logo, y, fb_logo_ex[i].n,
+ 0);
return y;
}
@@ -694,7 +768,11 @@ int fb_show_logo(struct fb_info *info, int rotate)
return 0;
count = fb_logo_count < 0 ? num_online_cpus() : fb_logo_count;
- y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, count);
+ #ifdef CONFIG_LOGO_SMALL
+ y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, count - (count / 2), count / 2);
+ #else
+ y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, count, 0);
+ #endif
y = fb_show_extra_logos(info, y, rotate);
return y;
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index 6d6f8c087..d6d7349f9 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -16,6 +16,12 @@ config FB_LOGO_EXTRA
depends on FB=y
default y if SPU_BASE
+config LOGO_SMALL
+ bool "Use a smaller logo for low-power CPUs"
+ help
+ Instead of displaying the normal logo for each CPU in the system,
+ use a small version of the logo for system CPUs that are low-power.
+
config LOGO_LINUX_MONO
bool "Standard black and white Linux logo"
default y
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment