/* SPDX-License-Identifier: GPL-2.0+ */ /* * UPL handoff generation * * Copyright 2024 Google LLC * Written by Simon Glass */ #ifndef __UPL_WRITE_H #define __UPL_WRITE_H #ifndef USE_HOSTCC #include #include #include struct unit_test_state; #define UPLP_ADDRESS_CELLS "#address-cells" #define UPLP_SIZE_CELLS "#size-cells" #define UPLN_OPTIONS "options" #define UPLN_UPL_PARAMS "upl-params" #define UPLP_SMBIOS "smbios" #define UPLP_ACPI "acpi" #define UPLP_BOOTMODE "bootmode" #define UPLP_ADDR_WIDTH "addr-width" #define UPLP_ACPI_NVS_SIZE "acpi-nvs-size" #define UPLPATH_UPL_IMAGE "/options/upl-image" #define UPLN_UPL_IMAGE "upl-image" #define UPLN_IMAGE "image" #define UPLP_FIT "fit" #define UPLP_CONF_OFFSET "conf-offset" #define UPLP_LOAD "load" #define UPLP_SIZE "size" #define UPLP_OFFSET "offset" #define UPLP_DESCRIPTION "description" #define UPLN_MEMORY "memory" #define UPLP_HOTPLUGGABLE "hotpluggable" #define UPLPATH_MEMORY_MAP "/memory-map" #define UPLN_MEMORY_MAP "memory-map" #define UPLP_USAGE "usage" #define UPLN_MEMORY_RESERVED "reserved-memory" #define UPLPATH_MEMORY_RESERVED "/reserved-memory" #define UPLP_NO_MAP "no-map" #define UPLN_SERIAL "serial" #define UPLP_REG "reg" #define UPLP_COMPATIBLE "compatible" #define UPLP_CLOCK_FREQUENCY "clock-frequency" #define UPLP_CURRENT_SPEED "current-speed" #define UPLP_REG_IO_SHIFT "reg-io-shift" #define UPLP_REG_OFFSET "reg-offset" #define UPLP_REG_IO_WIDTH "reg-io-width" #define UPLP_VIRTUAL_REG "virtual-reg" #define UPLP_ACCESS_TYPE "access-type" #define UPLN_GRAPHICS "framebuffer" #define UPLC_GRAPHICS "simple-framebuffer" #define UPLP_WIDTH "width" #define UPLP_HEIGHT "height" #define UPLP_STRIDE "stride" #define UPLP_GRAPHICS_FORMAT "format" /** * enum upl_boot_mode - Encodes the boot mode * * Each is a bit number from the boot_mode mask */ enum upl_boot_mode { UPLBM_FULL, UPLBM_MINIMAL, UPLBM_FAST, UPLBM_DIAG, UPLBM_DEFAULT, UPLBM_S2, UPLBM_S3, UPLBM_S4, UPLBM_S5, UPLBM_FACTORY, UPLBM_FLASH, UPLBM_RECOVERY, UPLBM_COUNT, }; /** * struct upl_image - UPL image informaiton * * @load: Address image was loaded to * @size: Size of image in bytes * @offset: Offset of the image in the FIT (0=none) * @desc: Description of the iamge (taken from the FIT) */ struct upl_image { ulong load; ulong size; uint offset; const char *description; }; /** * struct memregion - Information about a region of memory * * @base: Base address * @size: Size in bytes */ struct memregion { ulong base; ulong size; }; /** * struct upl_mem - Information about physical-memory layout * * TODO: Figure out initial-mapped-area * * @region: Memory region list (struct memregion) * @hotpluggable: true if hotpluggable */ struct upl_mem { struct alist region; bool hotpluggable; }; /** * enum upl_usage - Encodes the usage * * Each is a bit number from the usage mask */ enum upl_usage { UPLUS_ACPI_RECLAIM, UPLUS_ACPI_NVS, UPLUS_BOOT_CODE, UPLUS_BOOT_DATA, UPLUS_RUNTIME_CODE, UPLUS_RUNTIME_DATA, UPLUS_COUNT }; /** * struct upl_memmap - Information about logical-memory layout * * @name: Node name to use * @region: Memory region list (struct memregion) * @usage: Memory-usage mask (enum upl_usage) */ struct upl_memmap { const char *name; struct alist region; uint usage; }; /** * struct upl_memres - Reserved memory * * @name: Node name to use * @region: Reserved memory region list (struct memregion) * @no_map: true to indicate that a virtual mapping must not be created */ struct upl_memres { const char *name; struct alist region; bool no_map; }; enum upl_serial_access_type { UPLSAT_MMIO, UPLSAT_IO, }; /* serial defaults */ enum { UPLD_REG_IO_SHIFT = 0, UPLD_REG_OFFSET = 0, UPLD_REG_IO_WIDTH = 1, }; /** * enum upl_access_type - Access types * * @UPLAT_MMIO: Memory-mapped I/O * @UPLAT_IO: Separate I/O */ enum upl_access_type { UPLAT_MMIO, UPLAT_IO, }; /** * struct upl_serial - Serial console * * @compatible: Compatible string (NULL if there is no serial console) * @clock_frequency: Input clock frequency of UART * @current_speed: Current baud rate of UART * @reg: List of base address and size of registers (struct memregion) * @reg_shift_log2: log2 of distance between each register * @reg_offset: Offset of registers from the base address * @reg_width: Register width in bytes * @virtual_reg: Virtual register access (0 for none) * @access_type: Register access type to use */ struct upl_serial { const char *compatible; uint clock_frequency; uint current_speed; struct alist reg; uint reg_io_shift; uint reg_offset; uint reg_io_width; ulong virtual_reg; enum upl_serial_access_type access_type; }; /** * enum upl_graphics_format - Graphics formats * * @UPLGF_ARGB32: 32bpp format using 0xaarrggbb * @UPLGF_ABGR32: 32bpp format using 0xaabbggrr * @UPLGF_ARGB64: 64bpp format using 0xaaaabbbbggggrrrr */ enum upl_graphics_format { UPLGF_ARGB32, UPLGF_ABGR32, UPLGF_ABGR64, }; /** * @reg: List of base address and size of registers (struct memregion) * @width: Width of display in pixels * @height: Height of display in pixels * @stride: Number of bytes from one line to the next * @format: Pixel format */ struct upl_graphics { struct alist reg; uint width; uint height; uint stride; enum upl_graphics_format format; }; /* * Information about the UPL state * * @addr_cells: Number of address cells used in the handoff * @size_cells: Number of size cells used in the handoff * @bootmode: Boot-mode mask (enum upl_boot_mode) * @fit: Address of FIT image that was loaded * @conf_offset: Offset in FIT of the configuration that was selected * @addr_width: Adress-bus width of machine, e.g. 46 for 46 bits * @acpi_nvs_size: Size of the ACPI non-volatile-storage area in bytes * @image: Information about each image (struct upl_image) * @mem: Information about physical-memory regions (struct upl_mem) * @nennap: Information about logical-memory regions (struct upl_memmap) * @nennap: Information about reserved-memory regions (struct upl_memres) */ struct upl { int addr_cells; int size_cells; ulong smbios; ulong acpi; uint bootmode; ulong fit; uint conf_offset; uint addr_width; uint acpi_nvs_size; struct alist image; struct alist mem; struct alist memmap; struct alist memres; struct upl_serial serial; struct upl_graphics graphics; }; /** * upl_write_handoff() - Write a Unversal Payload handoff structure * * upl: UPL state to write * @root: root node to write it to * @skip_existing: Avoid recreating any nodes which already exist in the * devicetree. For example, if there is a serial node, just leave it alone, * since don't need to create a new one * Return: 0 on success, -ve on error */ int upl_write_handoff(const struct upl *upl, ofnode root, bool skip_existing); /** * upl_create_handoff_tree() - Write a Unversal Payload handoff structure * * upl: UPL state to write * @treep: Returns a new tree containing the handoff * Return: 0 on success, -ve on error */ int upl_create_handoff_tree(const struct upl *upl, oftree *treep); /** * upl_read_handoff() - Read a Unversal Payload handoff structure * * upl: UPL state to read into * @tree: Devicetree containing the data to read * Return: 0 on success, -ve on error */ int upl_read_handoff(struct upl *upl, oftree tree); /** * upl_get_test_data() - Fill a UPL with some test data * * @uts: Test state (can be uninited) * @upl: Returns test data * Return: 0 on success, 1 on error */ int upl_get_test_data(struct unit_test_state *uts, struct upl *upl); #endif /* USE_HOSTCC */ #if CONFIG_IS_ENABLED(UPL) && defined(CONFIG_XPL_BUILD) /** * upl_set_fit_info() - Set up basic info about the FIT * * @fit: Address of FIT * @conf_offset: Configuration node being used * @entry_addr: Entry address for next phase */ void upl_set_fit_info(ulong fit, int conf_offset, ulong entry_addr); /** * upl_set_fit_addr() - Set up the address of the FIT * * @fit: Address of FIT */ void upl_set_fit_addr(ulong fit); #else static inline void upl_set_fit_addr(ulong fit) {} static inline void upl_set_fit_info(ulong fit, int conf_offset, ulong entry_addr) {} #endif /* UPL && SPL */ /** * _upl_add_image() - Internal function to add a new image to the UPL * * @node: Image node offset in FIT * @load_addr: Address to which images was loaded * @size: Image size in bytes * @desc: Description of image * Return: 0 if OK, -ENOMEM if out of memory */ int _upl_add_image(int node, ulong load_addr, ulong size, const char *desc); /** * upl_add_image() - Add a new image to the UPL * * @fit: Pointer to FIT * @node: Image node offset in FIT * @load_addr: Address to which images was loaded * @size: Image size in bytes * Return: 0 if OK, -ENOMEM if out of memory */ static inline int upl_add_image(const void *fit, int node, ulong load_addr, ulong size) { if (CONFIG_IS_ENABLED(UPL) && IS_ENABLED(CONFIG_XPL_BUILD)) { const char *desc = fdt_getprop(fit, node, FIT_DESC_PROP, NULL); return _upl_add_image(node, load_addr, size, desc); } return 0; } /** upl_init() - Set up a UPL struct */ void upl_init(struct upl *upl); #endif /* __UPL_WRITE_H */