summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2024-08-09 16:03:21 -0600
committerTom Rini <[email protected]>2024-08-09 16:03:21 -0600
commitf4f845b859266790b97421f0740efce36bc9b8d2 (patch)
tree72a80e6e3a5e4b19c2c4ccdc5876da035bd745fb /common
parent49d7b206fb3a30553795fb5c1dd21573d82a98aa (diff)
parent3403422767650d3ff4f3129ee959e1b5de525161 (diff)
Merge patch series "Universal Payload initial series"
Simon Glass <[email protected]> says: Universal Payload (UPL) is an Industry Standard for firmware components[1]. UPL is designed to improve interoperability within the firmware industry, allowing mixing and matching of projects with less friction and fewer project-specific implementations. UPL is cross-platform, supporting ARM, x86 and RISC-V initially. This series provides some initial support for this, targeting 0.9.1 and sandbox only. Features still to come include: - Support for architectures - FIT validation - Handoff validation - Interoperability tests
Diffstat (limited to 'common')
-rw-r--r--common/board_f.c22
-rw-r--r--common/board_r.c2
-rw-r--r--common/spl/Makefile2
-rw-r--r--common/spl/spl.c8
-rw-r--r--common/spl/spl_fit.c9
-rw-r--r--common/spl/spl_upl.c172
6 files changed, 215 insertions, 0 deletions
diff --git a/common/board_f.c b/common/board_f.c
index 29e185137ad..d71005d9f83 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -40,6 +40,7 @@
#include <sysreset.h>
#include <timer.h>
#include <trace.h>
+#include <upl.h>
#include <video.h>
#include <watchdog.h>
#include <asm/cache.h>
@@ -859,6 +860,26 @@ __weak int clear_bss(void)
return 0;
}
+static int initf_upl(void)
+{
+ struct upl *upl;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_UPL_IN) || !(gd->flags & GD_FLG_UPL))
+ return 0;
+
+ upl = malloc(sizeof(struct upl));
+ if (upl)
+ ret = upl_read_handoff(upl, oftree_default());
+ if (ret) {
+ printf("UPL handoff: read failure (err=%dE)\n", ret);
+ return ret;
+ }
+ gd_set_upl(upl);
+
+ return 0;
+}
+
static const init_fnc_t init_sequence_f[] = {
setup_mon_len,
#ifdef CONFIG_OF_CONTROL
@@ -868,6 +889,7 @@ static const init_fnc_t init_sequence_f[] = {
trace_early_init,
#endif
initf_malloc,
+ initf_upl,
log_init,
initf_bootstage, /* uses its own timer, so does not need DM */
event_init,
diff --git a/common/board_r.c b/common/board_r.c
index d4ba245ac69..f445803d7a4 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -521,6 +521,8 @@ static int dm_announce(void)
uclass_count);
if (CONFIG_IS_ENABLED(OF_REAL))
printf(", devicetree: %s", fdtdec_get_srcname());
+ if (CONFIG_IS_ENABLED(UPL))
+ printf(", universal payload active");
printf("\n");
if (IS_ENABLED(CONFIG_OF_HAS_PRIOR_STAGE) &&
(gd->fdt_src == FDTSRC_SEPARATE ||
diff --git a/common/spl/Makefile b/common/spl/Makefile
index 4809f9c3ec1..137b18428bd 100644
--- a/common/spl/Makefile
+++ b/common/spl/Makefile
@@ -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
diff --git a/common/spl/spl.c b/common/spl/spl.c
index 7794ddccade..d6a364de6ee 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -810,6 +810,14 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
printf(SPL_TPL_PROMPT
"SPL hand-off write failed (err=%d)\n", ret);
}
+ if (CONFIG_IS_ENABLED(UPL_OUT) && (gd->flags & GD_FLG_UPL)) {
+ ret = spl_write_upl_handoff(&spl_image);
+ if (ret) {
+ printf(SPL_TPL_PROMPT
+ "UPL hand-off write failed (err=%d)\n", ret);
+ hang();
+ }
+ }
if (CONFIG_IS_ENABLED(BLOBLIST)) {
ret = bloblist_finish();
if (ret)
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index 2a097f4464c..1ad5a69d807 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -12,6 +12,7 @@
#include <memalign.h>
#include <mapmem.h>
#include <spl.h>
+#include <upl.h>
#include <sysinfo.h>
#include <asm/global_data.h>
#include <asm/io.h>
@@ -336,6 +337,8 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset,
image_info->entry_point = FDT_ERROR;
}
+ upl_add_image(fit, node, load_addr, length);
+
return 0;
}
@@ -847,6 +850,8 @@ int spl_load_simple_fit(struct spl_image_info *spl_image,
spl_image->entry_point = spl_image->load_addr;
spl_image->flags |= SPL_FIT_FOUND;
+ upl_set_fit_info(map_to_sysmem(ctx.fit), ctx.conf_node,
+ spl_image->entry_point);
return 0;
}
@@ -941,6 +946,10 @@ int spl_load_fit_image(struct spl_image_info *spl_image,
if (ret < 0)
return ret;
}
+ spl_image->flags |= SPL_FIT_FOUND;
+
+ upl_set_fit_info(map_to_sysmem(header), conf_noffset,
+ spl_image->entry_point);
return 0;
}
diff --git a/common/spl/spl_upl.c b/common/spl/spl_upl.c
new file mode 100644
index 00000000000..067d437150f
--- /dev/null
+++ b/common/spl/spl_upl.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * UPL handoff parsing
+ *
+ * Copyright 2024 Google LLC
+ * Written by Simon Glass <[email protected]>
+ */
+
+#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);
+}