Compare commits

..

25 Commits
glob ... prob2

Author SHA1 Message Date
Simon Glass
1ae3b1953b 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.

It also adds a more convenient 'write' subcommand.

END
Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
Series-links: 1:43
Series-version: 2
2025-10-02 09:42:43 -06:00
Simon Glass
7695d711e6 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-02 09:41:47 -06:00
Simon Glass
aa9d53d696 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-02 09:41:47 -06:00
Simon Glass
c4c6e183fd 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.

Series-changes: 2
- Use Canonical copyright

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
2025-10-02 09:41:47 -06:00
Simon Glass
0a592b5941 video: Add a write subcommand
This allows writing strings at particular positions on the display,
using either character or pixel positions.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
Suggested-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
2025-10-02 09:41:43 -06:00
Simon Glass
463328ec10 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.

Series-changes: 2
- Correct confusing output text which should be 16 instead of 10
- Improve docs for row and col

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
2025-10-02 09:24:50 -06:00
Simon Glass
42fc24044d video: Add tests for the video commands
Add a simple test for the setcurs and lcdputs commands.

Series-changes: 2
- Pull out the docs into a separate patch
- Update test result for hex

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
2025-10-02 09:05:38 -06:00
Simon Glass
3802cb3b87 doc: video: Add docs 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>

Series-changes: 2
- Split out docs into its own patch; use video: tag

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-10-02 09:05:37 -06:00
Simon Glass
7e6f668f70 cmd: Update setcurs to use hex
Commands in U-Boot should use hex consistently. Update this command
accordingly.

Series-changes: 2
- Add new patch to switch this command to use hex

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-10-02 08:53:17 -06:00
Simon Glass
e49052511f Merge branch 'glob2' into 'master'
boot: Support priority for global bootmeths

See merge request u-boot/u-boot!190
2025-10-01 16:11:55 +00:00
Simon Glass
999816ff78 boot: doc: Update for new global-bootmeth features
Provide some developer documentation on the priority feature for global
bootmeths.

Series-changes: 2
- Add a bit more detail suggested by Heinrich

Series-to: concept
Series-cc: heinrich
Cover-letter:
boot: Support priority for global bootmeths
At present global bootmeths always run first, before all other
bootmeths. Optimisations in the code take advantage of this, putting
them at the end, so they can be used once and then forgotten.

In some cases it is useful to run global bootmeths later in the boot.
For example, the EFI-bootmgr bootmeth may itself scan devices and the
network, so running it first can hold up the boot significantly for
boards not actually relying on EFI-bootmgr to boot.

This series introduces a new field in global bootmeths which indicates
the priority, using the same scheme as is used with bootdev hunters.
Thus it is possible to insert the EFI-bootmgr bootmeth just before the
hunter for network bootdevs is invoked.

Despite the simplicity of the concept and the relatively small series,
this is a fairly significant enhancement. It is also quite tricky to
implement, largely due to the way the original code was written, with
global bootmeths being a small, size-optimised add-on to the original
bootstd implementation.

For now we only allow each global bootmeth to run at most once, but this
implementation is written in a way that we could relax that if needed.
Then the bootmeth itself could decide whether to run at any particular
point in the bootflow iteration.

Size growth is about 390 bytes on Thumb2 (e.g. firefly-rk3288) if
CONFIG_BOOTMETH_GLOBAL is enabled, which it normally is. With that
disabled (which saves about 4K on the same platform), there is no
growth.
END

Signed-off-by: Simon Glass <sjg@chromium.org>
Series-links: 1:41
Series-version: 2
2025-09-30 17:24:09 -06:00
Simon Glass
9f00a0e3f3 boot: Run the EFI bootmgr just before network devices
At present the EFI bootmgr scans all devices in the system before
deciding which one to boot. Ideally it would use the bootstd iterator
for this, but in the meantime, give it a lower priority, so it runs
just before the network devices.

Note that if there are no hunted network devices hunted, then it will
run at the end, after all bootdevs are exhausted. In other words, it
will always run.

Series-changes: 2
- Update commit message to indicate the bootmeth will always run
- Document how the priority was chosen

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-09-30 17:23:58 -06:00
Simon Glass
6e4f842505 boot: Run global bootmeths after all bootdevs are exhausted
When there are no more bootdevs we should still go through the global
bootmeths, since some may not have yet been used, if their priority has
not yet come up.

Add a final check for this at the end of the iterator.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-09-30 17:14:45 -06:00
Simon Glass
1200d2b52f boot: Don't change the method count after global bootmeths
At present before scanning global bootmeths, the iterator sets the
method count to the index of the first global bootmeth. Now that we
support scanning the global bootmeths multiple times, we must leave this
count alone.

Check against have_global and first_glob_method instead.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-09-30 17:14:45 -06:00
Simon Glass
db66d8d149 boot: Implement a priority for global bootmeths
Allow bootmeths to select when they want to run, using the bootdev
priority. Provide a new bootmeth_glob_allowed() function which checks if
a bootmeth is ready to use.

Fix a comment in bootflow_system() which is a test for global bootmeths.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-09-30 17:14:45 -06:00
Simon Glass
1c54931b8e boot: Only run global bootmeths once each
Use the methods_done flags to make sure that each global bootmeth is
only used once. For now this has no effect, since they are all processed
at the start.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-09-30 17:14:45 -06:00
Simon Glass
8f4d910ee4 boot: Support rescanning the global bootmeths
Add the logic to scan through the global bootmeths for every new
bootdev, in preparation for allowing global bootmeths to select where in
the hunter ordering they go.

Use a new bootmeth_glob_allowed() function to check if a bootmeth is
allowed, ensuring that each can run at most once.

For now this has no actual effect, since the global bootmeths are
unconditionally processed at the start, with iter->methods_done being
updated to include all of them. Therefore when scanning again, no
unprocessed global bootmeths will be found.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-09-30 17:14:45 -06:00
Simon Glass
5fcdd37f14 boot: Move preparing bootdev into a function
The code at the end of iter_inc() is already somewhat tortuous. Before
making it worse, move it into a function.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-09-30 17:14:45 -06:00
Simon Glass
07326c0baf boot: Keep track of which bootmeths have been used
Add a bitfield which tracks when bootmeths have been used. This will be
needed when global bootmeths can be used later in the iteration.

Fix a missing bootflow_free() while here.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-09-30 17:14:45 -06:00
Simon Glass
37cabfe0b1 boot: Add a flag for whether there are global bootmeths
The current 'doing_global' refers to being in the state of processing
global bootmeths. Since global bootmeths are currently used once at the
start, it becomes false once the last global bootmeth has been used.

In preparation for allowing bootmeths to run at other points in the
bootstd interation, add a new 'have_global' flag which tracks whether
there are any global bootmeths in the method_order[] list. It is set up
when iteration starts. Unlike doing_global which resets back to false
after the global bootmeths have been handled, once have_global is set to
true, it remains true for the entire iteration process. This provides a
quick check as to whether global-bootmeth processing is needed.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-09-30 17:14:45 -06:00
Simon Glass
cd6424c4c3 boot: Update first_glob_method when dropping a bootmeth
For now we only support dropping non-global bootmeths from the
iteration. Update first_glob_method in that case and add a few checks
that things are correct.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-09-30 17:14:45 -06:00
Simon Glass
7e9ee27101 boot: Add a new test for global bootmeths
These have different behaviour from normal bootmeths and we are about to
enhance it. So add a test and also an extra check in bootflow_iter()

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-09-30 17:14:45 -06:00
Simon Glass
dcd69dc315 boot: Move showing of bootflows out of the command
It is helpful in tests to be able to show the bootflow that is being
examined. Move show_bootflow() into boot/ and rename it.

Series-changes: 2
- Add a log_err() for an invalid state

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-09-30 17:14:28 -06:00
Simon Glass
b69a2b1ef8 boot: Add more debugging to iter_incr()
This function is the core of the bootstd iteration. Add some debugging
for the decisions it makes along the way, to make it easier to track
what is going on.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-09-30 17:10:56 -06:00
Simon Glass
f89d2779c3 boot: Improve comments related to global bootmeths
Add a few comments about global bootmeths and first_glob_method

Fix a broken line in bootmeth_setup_iter_order() while we are here.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
2025-09-30 17:10:48 -06:00
19 changed files with 517 additions and 50 deletions

View File

@@ -97,6 +97,8 @@ static void report_bootflow_err(struct bootflow *bflow, int err)
printf("Ready");
break;
case BOOTFLOWST_COUNT:
log_err("Unexpected boot value of bootflow error %d",
bflow->state);
break;
}

View File

@@ -98,6 +98,14 @@ static int bootmeth_efi_mgr_bind(struct udevice *dev)
plat->desc = "EFI bootmgr flow";
plat->flags = BOOTMETHF_GLOBAL;
/*
* bootmgr scans all available devices which can take a while,
* especially for network devices. So choose the priority so that it
* comes just before the 'very slow' devices. This allows systems which
* don't rely on bootmgr to boot quickly, while allowing bootmgr to run
* on systems which need it.
*/
plat->glob_prio = BOOTDEVP_6_NET_BASE;
return 0;

View File

@@ -8,6 +8,7 @@
#include <command.h>
#include <dm.h>
#include <linker_lists.h>
#include <video.h>
#include <video_console.h>
@@ -22,8 +23,8 @@ static int do_video_setcursor(struct cmd_tbl *cmdtp, int flag, int argc,
if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev))
return CMD_RET_FAILURE;
col = dectoul(argv[1], NULL);
row = dectoul(argv[2], NULL);
col = hextoul(argv[1], NULL);
row = hextoul(argv[2], NULL);
vidconsole_position_cursor(dev, col, row);
return 0;
@@ -47,10 +48,86 @@ static int do_video_puts(struct cmd_tbl *cmdtp, int flag, int argc,
return ret ? CMD_RET_FAILURE : 0;
}
static int do_video_write(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
struct vidconsole_priv *priv;
bool use_pixels = false;
struct udevice *dev;
int ret, i;
if (argc < 3)
return CMD_RET_USAGE;
if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev))
return CMD_RET_FAILURE;
priv = dev_get_uclass_priv(dev);
/* Check for -p flag */
if (!strcmp(argv[1], "-p")) {
use_pixels = true;
argc--;
argv++;
}
if (argc < 3 || !(argc % 2))
return CMD_RET_USAGE;
for (i = 1; i < argc; i += 2) {
uint col, row;
char *pos = argv[i];
char *colon = strchr(pos, ':');
if (!colon)
return CMD_RET_USAGE;
col = hextoul(pos, NULL);
row = hextoul(colon + 1, NULL);
if (use_pixels)
vidconsole_set_cursor_pos(dev, col, row);
else
vidconsole_position_cursor(dev, col, row);
ret = vidconsole_put_string(dev, argv[i + 1]);
if (ret)
return CMD_RET_FAILURE;
}
ret = video_sync(dev->parent, false);
if (ret)
return CMD_RET_FAILURE;
return 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",
" <col> <row> in character"
" <col> <row> in hex characters"
);
U_BOOT_CMD(
@@ -58,3 +135,16 @@ 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 write [-p] [<col>:<row> <string>]... - Write strings at specified positions\n"
" -p: Use pixel coordinates instead of character positions\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(write, CONFIG_SYS_MAXARGS, 1, do_video_write),
U_BOOT_SUBCMD_MKENT(images, 1, 1, do_video_images));

View File

@@ -717,8 +717,9 @@ to the next partition, or bootdev, for example. The special values
`BF_NO_MORE_PARTS` and `BF_NO_MORE_DEVICES` handle this. When `iter_incr` sees
`BF_NO_MORE_PARTS` it knows that it should immediately move to the next bootdev.
When it sees `BF_NO_MORE_DEVICES` it knows that there is nothing more it can do
so it should immediately return. The caller of `iter_incr()` is responsible for
updating the `err` field, based on the return value it sees.
so it should immediately run any unused global bootmeths and then return. The
caller of `iter_incr()` is responsible for updating the `err` field, based on
the return value it sees.
Global bootmeths can have a non-zero priority, which indicates where in the
iteration sequence they should run. Each time a new bootdev is produced by a
@@ -732,6 +733,15 @@ Assuming they are enabled and the iteration sequence runs right to the end, all
global bootmeths will be used. This is handled by a special case at the end of
iter_incr(), where it processes amy so-far-unused global bootmeths.
It is important to note the special nature of global bootmeths, with respect to
priority. If there are two normal bootmeths and a global one, the normal ones
are run for each bootdev, but the global one is independent of bootdevs. The
order might be:
bootdev priority 3: normal-1, normal-3
global-2, prio 4
bootdev priority 5: normal-1, normal-3
Of course if a specific bootmeth ordering is provided, then this overrides the
default ordering. Global bootmeths must be listed at the end, reflecting their
hybrid nature (they are bootmeths but operate on the system as a whole, not on

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.

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

@@ -0,0 +1,57 @@
.. 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 hex, with 0 being the left side. Note that this is the
text-column position, so the number of pixels per position depends on the
font size.
row
Row position in hex, with 0 being the top edge. Note that this is the
text-row position, so the number of pixels per position depends on the
font size.
Examples
--------
Set cursor to column 0x10, 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.

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

@@ -0,0 +1,120 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
.. index::
single: video (command)
video command
=============
Synopsis
--------
::
video setcursor <col> <row>
video puts <string>
video write [-p] [<col>:<row> <string>]...
video images
Description
-----------
The video command provides access to the video-console subsystem. Common
arguments are as follows:
col
Column position in hex, with 0 being the left side. Note that this is the
text-column position, so the number of pixels per position depends on the
font size.
row
Row position in hex, with 0 being the top edge. Note that this is the
text-row position, so the number of pixels per position depends on the
font size.
video setcursor
~~~~~~~~~~~~~~~
video setcursor <col> <row>
Set the cursor position on the video console.
video puts
~~~~~~~~~~
video puts <string>
Write a string to the video console at the current cursor position.
string
Text string to display
video write
~~~~~~~~~~~
video write [-p] [<col>:<row> <string>]...
Write one or more strings to the video console at specified positions. Each
position/string pair sets the cursor to the specified location and writes the
string. Multiple position/string pairs can be provided to write to multiple
locations in a single command.
-p
Use pixel coordinates instead of character positions. When specified, the
col and row values are interpreted as pixel offsets and converted to
character positions based on the current font size.
string
Text string to display at the specified position
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 16"
Write text at multiple positions::
=> video write 0:0 "Top left" 0:a "Line 10"
=> video write 0:a "First column in line10" 2a:0 "Text column 42"
Write text using pixel coordinates::
=> video write -p 0:0 "Top left corner" a0:80 "Pixel position"
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 Canonical Ltd
* Written by Simon Glass <simon.glass@canonical.com>
*/
#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,53 @@ 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(187, 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));
ut_assertok(run_command(
"video write 14:6 \"Multi\" 19:7 \"Write\"", 0));
ut_asserteq(381, video_compress_fb(uts, dev, false));
ut_assertok(video_check_copy_fb(uts, dev));
ut_assertok(run_command("video write -p a3:34 \"Pixels\"", 0));
ut_asserteq(440, 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);