mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-27 06:04:40 +08:00
upl: Add support for Universal Payload in SPL
Add the basic code to create a handoff structure in SPL, so it can be passed to the next phase. For now this is not plumbed in. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
264f4b0b34
commit
fefb53492f
@ -1715,6 +1715,7 @@ S: Maintained
|
||||
T: git https://source.denx.de/u-boot/custodians/u-boot-dm.git
|
||||
F: boot/upl*
|
||||
F: cmd/upl.c
|
||||
F: common/spl/spl_upl.c
|
||||
F: doc/usage/cmd/upl.rst
|
||||
F: include/upl.h
|
||||
F: test/boot/upl.c
|
||||
|
32
boot/Kconfig
32
boot/Kconfig
@ -750,6 +750,7 @@ config UPL
|
||||
imply CMD_UPL
|
||||
imply UPL_READ
|
||||
imply UPL_WRITE
|
||||
imply SPL_UPL if SPL
|
||||
help
|
||||
Provides support for UPL payloads and handoff information. U-Boot
|
||||
supports generating and accepting handoff information. The mkimage
|
||||
@ -766,11 +767,42 @@ config UPL_READ
|
||||
|
||||
config UPL_WRITE
|
||||
bool "upl - Support writing a Universal Payload handoff"
|
||||
help
|
||||
Provides support for encoding a UPL-format payload from a C structure
|
||||
so it can be passed to another program. This is just the writing
|
||||
implementation, useful for trying it out. See SPL_UPL_OUT
|
||||
for how to tell U-Boot SPL to actually write it before jumping to
|
||||
the next phase.
|
||||
|
||||
if SPL
|
||||
|
||||
config SPL_UPL
|
||||
bool "Write a UPL handoff in SPL"
|
||||
imply SPL_UPL_OUT
|
||||
help
|
||||
This tells SPL to write a UPL handoff and pass it to the next phase
|
||||
(e.g. to U-Boot or another program which SPL loads and runs). THis
|
||||
provides information to help that program run correctly and
|
||||
efficiently on the machine.
|
||||
|
||||
config SPL_UPL_WRITE
|
||||
bool # upl - Support writing a Universal Payload handoff in SPL
|
||||
select SPL_BLOBLIST
|
||||
help
|
||||
Provides support for encoding a UPL-format payload from a C structure
|
||||
so it can be passed to another program. This is just the writing
|
||||
implementation, useful for trying it out.
|
||||
|
||||
config SPL_UPL_OUT
|
||||
bool "upl - Support writing a Universal Payload handoff in SPL"
|
||||
select SPL_UPL_WRITE
|
||||
help
|
||||
Provides support for encoding a UPL-format payload and passing it to
|
||||
the next firmware phase. This allows U-Boot SPL to function as
|
||||
Platform Init in the meaning of the specification.
|
||||
|
||||
endif # SPL
|
||||
|
||||
endif # UPL
|
||||
|
||||
endif # BOOTSTD
|
||||
|
@ -37,3 +37,5 @@ obj-$(CONFIG_$(SPL_TPL_)SPI_LOAD) += spl_spi.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)RAM_SUPPORT) += spl_ram.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)USB_SDP_SUPPORT) += spl_sdp.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_$(SPL_TPL_)UPL) += spl_upl.o
|
||||
|
172
common/spl/spl_upl.c
Normal file
172
common/spl/spl_upl.c
Normal file
@ -0,0 +1,172 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* UPL handoff parsing
|
||||
*
|
||||
* Copyright 2024 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY UCLASS_BOOTSTD
|
||||
|
||||
#include <alist.h>
|
||||
#include <bloblist.h>
|
||||
#include <dm.h>
|
||||
#include <image.h>
|
||||
#include <mapmem.h>
|
||||
#include <serial.h>
|
||||
#include <spl.h>
|
||||
#include <upl.h>
|
||||
#include <video.h>
|
||||
#include <asm/global_data.h>
|
||||
#include <dm/read.h>
|
||||
#include <dm/uclass-internal.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct upl s_upl;
|
||||
|
||||
void upl_set_fit_addr(ulong fit)
|
||||
{
|
||||
struct upl *upl = &s_upl;
|
||||
|
||||
upl->fit = fit;
|
||||
}
|
||||
|
||||
void upl_set_fit_info(ulong fit, int conf_offset, ulong entry_addr)
|
||||
{
|
||||
struct upl *upl = &s_upl;
|
||||
|
||||
upl->fit = fit;
|
||||
upl->conf_offset = conf_offset;
|
||||
log_debug("upl: add fit %lx conf %x\n", fit, conf_offset);
|
||||
}
|
||||
|
||||
int _upl_add_image(int node, ulong load_addr, ulong size, const char *desc)
|
||||
{
|
||||
struct upl *upl = &s_upl;
|
||||
struct upl_image img;
|
||||
|
||||
img.load = load_addr;
|
||||
img.size = size;
|
||||
img.offset = node;
|
||||
img.description = desc;
|
||||
if (!alist_add(&upl->image, img))
|
||||
return -ENOMEM;
|
||||
log_debug("upl: add image %s at %lx size %lx\n", desc, load_addr, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_serial(struct upl_serial *ser)
|
||||
{
|
||||
struct udevice *dev = gd->cur_serial_dev;
|
||||
struct serial_device_info info;
|
||||
struct memregion region;
|
||||
int ret;
|
||||
|
||||
if (!dev)
|
||||
return log_msg_ret("ser", -ENOENT);
|
||||
ret = serial_getinfo(dev, &info);
|
||||
if (ret)
|
||||
return log_msg_ret("inf", ret);
|
||||
|
||||
ser->compatible = ofnode_read_string(dev_ofnode(dev), "compatible");
|
||||
ser->clock_frequency = info.clock;
|
||||
ser->current_speed = gd->baudrate;
|
||||
region.base = info.addr;
|
||||
region.size = info.size;
|
||||
alist_init_struct(&ser->reg, struct memregion);
|
||||
if (!alist_add(&ser->reg, region))
|
||||
return -ENOMEM;
|
||||
ser->reg_io_shift = info.reg_shift;
|
||||
ser->reg_offset = info.reg_offset;
|
||||
ser->reg_io_width = info.reg_width;
|
||||
ser->virtual_reg = 0;
|
||||
ser->access_type = info.addr_space;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_graphics(struct upl_graphics *gra)
|
||||
{
|
||||
struct video_uc_plat *plat;
|
||||
struct video_priv *priv;
|
||||
struct memregion region;
|
||||
struct udevice *dev;
|
||||
|
||||
alist_init_struct(&gra->reg, struct memregion);
|
||||
uclass_find_first_device(UCLASS_VIDEO, &dev);
|
||||
if (!dev || !device_active(dev))
|
||||
return log_msg_ret("vid", -ENOENT);
|
||||
|
||||
plat = dev_get_uclass_plat(dev);
|
||||
region.base = plat->base;
|
||||
region.size = plat->size;
|
||||
if (!alist_add(&gra->reg, region))
|
||||
return log_msg_ret("reg", -ENOMEM);
|
||||
|
||||
priv = dev_get_uclass_priv(dev);
|
||||
gra->width = priv->xsize;
|
||||
gra->height = priv->ysize;
|
||||
gra->stride = priv->line_length; /* private field */
|
||||
switch (priv->format) {
|
||||
case VIDEO_RGBA8888:
|
||||
case VIDEO_X8R8G8B8:
|
||||
gra->format = UPLGF_ARGB32;
|
||||
break;
|
||||
case VIDEO_X8B8G8R8:
|
||||
gra->format = UPLGF_ABGR32;
|
||||
break;
|
||||
case VIDEO_X2R10G10B10:
|
||||
log_debug("device '%s': VIDEO_X2R10G10B10 not supported\n",
|
||||
dev->name);
|
||||
return log_msg_ret("for", -EPROTO);
|
||||
case VIDEO_UNKNOWN:
|
||||
log_debug("device '%s': Unknown video format\n", dev->name);
|
||||
return log_msg_ret("for", -EPROTO);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spl_write_upl_handoff(struct spl_image_info *spl_image)
|
||||
{
|
||||
struct upl *upl = &s_upl;
|
||||
struct abuf buf;
|
||||
ofnode root;
|
||||
void *ptr;
|
||||
int ret;
|
||||
|
||||
log_debug("UPL: Writing handoff - image_count=%d\n", upl->image.count);
|
||||
upl->addr_cells = IS_ENABLED(CONFIG_PHYS_64BIT) ? 2 : 1;
|
||||
upl->size_cells = IS_ENABLED(CONFIG_PHYS_64BIT) ? 2 : 1;
|
||||
upl->bootmode = UPLBM_DEFAULT;
|
||||
ret = write_serial(&upl->serial);
|
||||
if (ret)
|
||||
return log_msg_ret("ser", ret);
|
||||
ret = write_graphics(&upl->graphics);
|
||||
if (ret && ret != -ENOENT)
|
||||
return log_msg_ret("gra", ret);
|
||||
|
||||
root = ofnode_root();
|
||||
ret = upl_write_handoff(upl, root, true);
|
||||
if (ret)
|
||||
return log_msg_ret("wr", ret);
|
||||
|
||||
ret = oftree_to_fdt(oftree_default(), &buf);
|
||||
if (ret)
|
||||
return log_msg_ret("fdt", ret);
|
||||
log_debug("FDT size %zx\n", abuf_size(&buf));
|
||||
|
||||
ptr = bloblist_add(BLOBLISTT_CONTROL_FDT, abuf_size(&buf), 0);
|
||||
if (!ptr)
|
||||
return log_msg_ret("blo", -ENOENT);
|
||||
memcpy(ptr, abuf_data(&buf), abuf_size(&buf));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spl_upl_init(void)
|
||||
{
|
||||
upl_init(&s_upl);
|
||||
}
|
@ -1073,4 +1073,20 @@ static inline bool spl_decompression_enabled(void)
|
||||
{
|
||||
return IS_ENABLED(CONFIG_SPL_GZIP) || IS_ENABLED(CONFIG_SPL_LZMA);
|
||||
}
|
||||
|
||||
/**
|
||||
* spl_write_upl_handoff() - Write a Universal Payload hand-off structure
|
||||
*
|
||||
* @spl_image: Information about the image being booted
|
||||
* Return: 0 if OK, -ve on error
|
||||
*/
|
||||
int spl_write_upl_handoff(struct spl_image_info *spl_image);
|
||||
|
||||
/**
|
||||
* spl_upl_init() - Get UPL ready for information to be added
|
||||
*
|
||||
* This must be called before upl_add_image(), etc.
|
||||
*/
|
||||
void spl_upl_init(void);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user