Compare commits

...

6 Commits

Author SHA1 Message Date
Simon Glass
ecfaa2cd48 video: Provide a command to list built-in images
Add a new 'video images' command which lists the graphical images that
are compiled into U-Boot. Generally the only one is the logo.

Series-to: concept
Series-cc: heinrich
Cover-letter:
video: Tidy up embedded graphical images
U-Boot includes a few graphical images which are compiled in, such as
the logo and the BGRT logo used for EFI.

At present these are handled by a Makefile rule which looks for files
ending with '_logo.bmp'.

This series moves these into a new drivers/video/images directory and
puts them in a linker list, so it is possible to see what images are
available.

Adding a new image is simpler, just requiring the addition of the normal
'obj-y += file.bmp' rule.

This series also adds a new 'video' command which provides the existing
'setcurs' and 'lcdputs' as subcommands, along with documentation and
tests.
END
Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
2025-10-01 17:04:50 -06:00
Simon Glass
431605bedb acpi: bgrt: Move the BGRT image into the images directory
Move the BGRT image to use the same video_image linker-list approach
as the other embedded image. Move it into the drivers/video/images
directory and rename it to 'bgrt.bmp' since we know it is an image.

Drop the old bgrt Makefile rule as it is no-longer needed.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
2025-10-01 17:04:43 -06:00
Simon Glass
d8f07c16ff video: Move the logo into the new video-images directory
Move u_boot_logo.bmp into drivers/video/images and include it in the
build.

Make use of the new video_image_get() macro to obtain the logo.

Drop the old SPLASH_...() macros.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
2025-10-01 17:04:19 -06:00
Simon Glass
cf1ed72377 video: Support a linker list of images
It is inconvenient to have to access graphical images as independent
symbols. Create a new rule which handles any file mentioned in
drivers/video/images/Makefile

For each graphical image, embed in the image and create a linker-list
entry for it.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
2025-10-01 17:04:19 -06:00
Simon Glass
1ce962ec34 video: Add video command with subcommands
Add a new 'video' command with 'setcursor' and 'puts' subcommands that
provide an alternative interface to the existing setcurs and lcdputs
commands.

Update the test is updated to test both the legacy commands and the new
'video' command.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
2025-10-01 17:04:19 -06:00
Simon Glass
38266d911a video: doc: Add docs and tests for video commands
Add documentation and a simple test for the setcurs and lcdputs
commands.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
2025-10-01 17:04:18 -06:00
16 changed files with 388 additions and 45 deletions

View File

@@ -8,6 +8,7 @@
#include <command.h>
#include <dm.h>
#include <linker_lists.h>
#include <video.h>
#include <video_console.h>
@@ -47,6 +48,29 @@ static int do_video_puts(struct cmd_tbl *cmdtp, int flag, int argc,
return ret ? CMD_RET_FAILURE : 0;
}
static int do_video_images(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
struct video_image *image;
int count, i;
image = ll_entry_start(struct video_image, video_image);
count = ll_entry_count(struct video_image, video_image);
printf("%-20s %10s\n", "Name", "Size");
printf("%-20s %10s\n", "--------------------", "----------");
for (i = 0; i < count; i++, image++) {
ulong size = (ulong)image->end - (ulong)image->begin;
printf("%-20s %10lu\n", image->name, size);
}
printf("\nTotal images: %d\n", count);
return 0;
}
U_BOOT_CMD(
setcurs, 3, 1, do_video_setcursor,
"set cursor position within screen",
@@ -58,3 +82,13 @@ U_BOOT_CMD(
"print string on video framebuffer",
" <string>"
);
U_BOOT_LONGHELP(video,
"setcursor <col> <row> - Set cursor position\n"
"video puts <string> - Write string at current position\n"
"video images - List images compiled into U-Boot");
U_BOOT_CMD_WITH_SUBCMDS(video, "Video commands", video_help_text,
U_BOOT_SUBCMD_MKENT(setcursor, 3, 1, do_video_setcursor),
U_BOOT_SUBCMD_MKENT(puts, 2, 1, do_video_puts),
U_BOOT_SUBCMD_MKENT(images, 1, 1, do_video_images));

58
doc/usage/cmd/lcdputs.rst Normal file
View File

@@ -0,0 +1,58 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
.. index::
single: lcdputs (command)
lcdputs command
===============
Synopsis
--------
::
lcdputs <string>
Description
-----------
The lcdputs command prints a string to the video framebuffer at the current
cursor position.
string
Text string to display on the video console
Examples
--------
Print a simple string::
=> lcdputs "Hello World"
Combine with setcurs to position text::
=> setcurs 10 5
=> lcdputs "Positioned text"
Print multiple lines::
=> setcurs 0 0
=> lcdputs "Line 1"
=> setcurs 0 1
=> lcdputs "Line 2"
Configuration
-------------
The lcdputs command is available if CONFIG_CMD_VIDEO=y.
See also
--------
* :doc:`video` - video command with subcommands
* :doc:`setcurs` - set cursor position
Return value
------------
The return value $? is 0 (true) on success, 1 (false) on failure.

53
doc/usage/cmd/setcurs.rst Normal file
View File

@@ -0,0 +1,53 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
.. index::
single: setcurs (command)
setcurs command
===============
Synopsis
--------
::
setcurs <col> <row>
Description
-----------
The setcurs command sets the cursor position on the video console.
col
Column position in pixels (0-based)
row
Row position in pixels (0-based)
Examples
--------
Set cursor to column 10, row 5::
=> setcurs 10 5
Move cursor to top left::
=> setcurs 0 0
Configuration
-------------
The setcurs command is available if CONFIG_CMD_VIDEO=y.
See also
--------
* :doc:`video` - video command with subcommands
* :doc:`lcdputs` - print string on video framebuffer
Return value
------------
The return value $? is 0 (true) on success, 1 (false) on failure.

85
doc/usage/cmd/video.rst Normal file
View File

@@ -0,0 +1,85 @@
.. index::
single: video (command)
video command
=============
Synopsis
--------
::
video setcursor <col> <row>
video puts <string>
video images
Description
-----------
The video command provides access to the video-console subsystem.
video setcursor
~~~~~~~~~~~~~~~
video setcursor <col> <row>
Set the cursor position on the video console.
col
Column position in pixels (0-based)
row
Row position in pixels (0-based)
video puts
~~~~~~~~~~
video puts <string>
Write a string to the video console at the current cursor position.
string
Text string to display
video images
~~~~~~~~~~~~
video images
List all images that are compiled into U-Boot. This shows the name and size
of each image that was built from .bmp files in the drivers/video/images
directory.
Examples
--------
Set cursor and print text::
=> video setcursor 10 5
=> video puts "Hello World"
Print at different positions::
=> video setcursor 0 0
=> video puts "Top left"
=> video setcursor 0 10
=> video puts "Line 10"
List compiled-in images::
=> video images
Name Size
-------------------- ----------
u_boot 6932
Total images: 1
Configuration
-------------
The video command is available if CONFIG_CMD_VIDEO=y.
Return value
------------
The return value $? is 0 (true) on success, 1 (false) on failure.

View File

@@ -85,6 +85,7 @@ Shell commands
cmd/if
cmd/itest
cmd/imxtract
cmd/lcdputs
cmd/load
cmd/loadb
cmd/loadm
@@ -117,6 +118,7 @@ Shell commands
cmd/scmi
cmd/scp03
cmd/seama
cmd/setcurs
cmd/setexpr
cmd/sf
cmd/shim
@@ -135,6 +137,7 @@ Shell commands
cmd/ums
cmd/unbind
cmd/ut
cmd/video
cmd/virtio
cmd/wdt
cmd/wget

View File

@@ -24,7 +24,6 @@ obj-$(CONFIG_$(PHASE_)PANEL) += panel-uclass.o
obj-$(CONFIG_PANEL_HX8238D) += hx8238d.o
obj-$(CONFIG_$(PHASE_)SIMPLE_PANEL) += simple_panel.o
obj-$(CONFIG_VIDEO_LOGO) += u_boot_logo.o
obj-$(CONFIG_$(PHASE_)BMP) += bmp.o
obj-y += vesa_helper.o
@@ -86,3 +85,5 @@ obj-$(CONFIG_VIDEO_ZYNQMP_DPSUB) += zynqmp/
obj-y += bridge/
obj-y += sunxi/
obj-y += tegra20/
obj-y += images/

View File

@@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright 2025 Simon Glass <sjg@chromium.org>
obj-$(CONFIG_VIDEO_LOGO) += u_boot.o
ifdef CONFIG_$(PHASE_)GENERATE_ACPI_TABLE
obj-y += bgrt.o
endif

View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@@ -581,28 +581,24 @@ int video_get_ysize(struct udevice *dev)
return priv->ysize;
}
#define SPLASH_DECL(_name) \
extern u8 __splash_ ## _name ## _begin[]; \
extern u8 __splash_ ## _name ## _end[]
#define SPLASH_START(_name) __splash_ ## _name ## _begin
#define SPLASH_END(_name) __splash_ ## _name ## _end
SPLASH_DECL(u_boot_logo);
void *video_get_u_boot_logo(int *sizep)
{
if (sizep)
*sizep = SPLASH_END(u_boot_logo) - SPLASH_START(u_boot_logo);
void *ptr;
int size;
return SPLASH_START(u_boot_logo);
ptr = video_image_get(u_boot, &size);
if (sizep)
*sizep = size;
return ptr;
}
static int show_splash(struct udevice *dev)
{
u8 *data = SPLASH_START(u_boot_logo);
u8 *data;
int ret;
data = video_image_getptr(u_boot);
ret = video_bmp_display(dev, map_to_sysmem(data), -4, 4, true);
return 0;

View File

@@ -7,7 +7,9 @@
#ifndef _VIDEO_H_
#define _VIDEO_H_
#include <linker_lists.h>
#include <stdio_dev.h>
#include <video_image.h>
#ifdef CONFIG_SANDBOX
#include <asm/state.h>
#endif
@@ -201,6 +203,50 @@ enum colour_idx {
VID_COLOUR_COUNT
};
/**
* struct video_image - Information about an embedded image
*
* This structure holds the pointers to the start and end of an image
* that is embedded in the U-Boot binary, along with its name.
* On 64-bit: 2*8 + VIDEO_IMAGE_NAMELEN = 32 bytes
* On 32-bit: 2*4 + VIDEO_IMAGE_NAMELEN = 24 bytes
*
* @begin: Pointer to the start of the image data
* @end: Pointer to the end of the image data
* @name: Name of the image (e.g., "u_boot", "canonical"), null-terminated
*/
struct video_image {
const void *begin;
const void *end;
char name[VIDEO_IMAGE_NAMELEN];
};
/**
* video_image_get() - Get the start address and size of an image
*
* @_name: Name of the image taken from filename (e.g. u_boot)
* @_sizep: Returns the size of the image in bytes
* Return: Pointer to the start of the image data
*/
#define video_image_get(_name, _sizep) ({ \
struct video_image *__img = ll_entry_get(struct video_image, _name, \
video_image); \
*(_sizep) = (ulong)__img->end - (ulong)__img->begin; \
(void *)__img->begin; \
})
/**
* video_image_getptr() - Get the start address of an image
*
* @_name: Name of the image taken from filename (e.g. u_boot)
* Return: Pointer to the start of the image data
*/
#define video_image_getptr(_name) ({ \
struct video_image *__img = ll_entry_get(struct video_image, _name, \
video_image); \
(void *)__img->begin; \
})
/**
* video_index_to_colour() - convert a color code to a pixel's internal
* representation

13
include/video_image.h Normal file
View File

@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2025 Google LLC
* Written by Simon Glass <sjg@chromium.org>
*/
#ifndef __VIDEO_IMAGE_H
#define __VIDEO_IMAGE_H
/* Maximum length of an embedded image name */
#define VIDEO_IMAGE_NAMELEN 16
#endif /* __VIDEO_IMAGE_H */

View File

@@ -12,8 +12,6 @@ obj-$(CONFIG_$(PHASE_)ACPIGEN) += acpi_table.o
obj-y += acpi_extra.o
obj-y += acpi_writer.o
obj-y += bgrt_image.o
# With QEMU the ACPI tables come from there, not from U-Boot
ifndef CONFIG_QFW_ACPI
obj-y += base.o

View File

@@ -13,23 +13,6 @@
#include <video.h>
#include <acpi/acpi_table.h>
#define BGRT_DECL(_name) \
extern u8 __bgrt_ ## _name ## _begin[]; \
extern u8 __bgrt_ ## _name ## _end[]
#define BGRT_START(_name) __bgrt_ ## _name ## _begin
#define BGRT_END(_name) __bgrt_ ## _name ## _end
BGRT_DECL(image);
static void *bgrt_get_image(int *sizep)
{
if (sizep)
*sizep = BGRT_END(image) - BGRT_START(image);
return BGRT_START(image);
}
int acpi_write_bgrt(struct acpi_ctx *ctx)
{
struct udevice *dev;
@@ -42,7 +25,10 @@ int acpi_write_bgrt(struct acpi_ctx *ctx)
/* If video is available, use the screen size to centre the logo */
have_video = !uclass_first_device_err(UCLASS_VIDEO, &dev);
logo = bgrt_get_image(&size);
if (!IS_ENABLED(CONFIG_VIDEO))
return -ENOENT;
logo = video_image_get(bgrt, &size);
/* If there's no logo data, there's nothing to report */
if (!logo)

View File

@@ -523,23 +523,43 @@ cmd_S_splash= \
$(obj)/%_logo.S: $(src)/%_logo.bmp
$(call cmd,S_splash)
# Generate an assembly file to wrap the EFI 'Boot Graphics Resource Table' image
quiet_cmd_S_bgrt= BGRT $@
# Modified for U-Boot
cmd_S_bgrt= \
# Handle image files in drivers/video/images without _logo suffix
# Generate an assembly file to wrap the image data and create a linker-list entry
quiet_cmd_S_image= IMAGE $@
cmd_S_image= \
( \
echo '.section .rodata.bgrt.init,"a"'; \
echo '\#include <video_image.h>'; \
echo '.section .rodata.image.init,"a"'; \
echo '.balign 16'; \
echo '.global __$(*F)_image_begin'; \
echo '__$(*F)_image_begin:'; \
echo '.global __image_$(*F)_begin'; \
echo '__image_$(*F)_begin:'; \
echo '.incbin "$<" '; \
echo '__$(*F)_image_end:'; \
echo '.global __$(*F)_image_end'; \
echo '__image_$(*F)_end:'; \
echo '.global __image_$(*F)_end'; \
echo '.balign 16'; \
echo ''; \
echo '/* Linker list entry for this image */'; \
echo '.section __u_boot_list_2_video_image_2_$(*F), "aw"'; \
echo '.balign 8'; \
echo '.global _u_boot_list_2_video_image_2_$(*F)'; \
echo '_u_boot_list_2_video_image_2_$(*F):'; \
echo '\#ifdef __LP64__'; \
echo '.quad __image_$(*F)_begin'; \
echo '.quad __image_$(*F)_end'; \
echo '.asciz "'$(*F)'"'; \
echo '.org _u_boot_list_2_video_image_2_$(*F) + 16 + VIDEO_IMAGE_NAMELEN'; \
echo '\#else'; \
echo '.long __image_$(*F)_begin'; \
echo '.long __image_$(*F)_end'; \
echo '.asciz "'$(*F)'"'; \
echo '.org _u_boot_list_2_video_image_2_$(*F) + 8 + VIDEO_IMAGE_NAMELEN'; \
echo '\#endif'; \
) > $@
$(obj)/%_image.S: $(src)/%_image.bmp
$(call cmd,S_bgrt)
ifneq ($(filter drivers/video/images,$(obj)),)
$(obj)/%.S: $(src)/%.bmp
$(call cmd,S_image)
endif
# EFI applications
# A Makefile target *.efi is built as EFI application.

View File

@@ -1080,3 +1080,44 @@ static int dm_test_video_backspace_truetype(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_video_backspace_truetype, UTF_SCAN_PDATA | UTF_SCAN_FDT);
/* video commands */
static int dm_test_video_cmd(struct unit_test_state *uts)
{
struct udevice *dev, *con;
ut_assertok(select_vidconsole(uts, "vidconsole0"));
ut_assertok(video_get_nologo(uts, &dev));
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
ut_assertok(vidconsole_select_font(con, "8x16", 0));
ut_assertok(run_command("setcurs 10 5", 0));
ut_assertok(run_command("lcdputs \"Test string\"", 0));
ut_asserteq(188, video_compress_fb(uts, dev, false));
ut_assertok(video_check_copy_fb(uts, dev));
ut_assertok(run_command("video setcursor 0 0", 0));
ut_assertok(run_command("video puts \"Top left\"", 0));
ut_asserteq(272, video_compress_fb(uts, dev, false));
ut_assertok(video_check_copy_fb(uts, dev));
return 0;
}
DM_TEST(dm_test_video_cmd, UTF_SCAN_PDATA | UTF_SCAN_FDT);
/* video images command */
static int dm_test_video_images(struct unit_test_state *uts)
{
ut_assertok(run_command("video images", 0));
ut_assert_nextline("Name Size");
ut_assert_nextline("-------------------- ----------");
ut_assert_nextline("bgrt 43926");
ut_assert_nextline("u_boot 6932");
ut_assert_skip_to_line("");
ut_assert_nextline("Total images: 2");
ut_assert_console_end();
return 0;
}
DM_TEST(dm_test_video_images, UTF_SCAN_PDATA | UTF_SCAN_FDT | UTF_CONSOLE);