spl.h 15.8 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * (C) Copyright 2012
 * Texas Instruments, <www.ti.com>
 */
#ifndef	_SPL_H_
#define	_SPL_H_

#include <binman_sym.h>

/* Platform-specific defines */
#include <linux/compiler.h>
#include <asm/spl.h>
#include <handoff.h>

/* Value in r0 indicates we booted from U-Boot */
#define UBOOT_NOT_LOADED_FROM_SPL	0x13578642

/* Boot type */
#define MMCSD_MODE_UNDEFINED	0
#define MMCSD_MODE_RAW		1
#define MMCSD_MODE_FS		2
#define MMCSD_MODE_EMMCBOOT	3

/*
 * u_boot_first_phase() - check if this is the first U-Boot phase
 *
 * U-Boot has up to three phases: TPL, SPL and U-Boot proper. Depending on the
 * build flags we can determine whether the current build is for the first
 * phase of U-Boot or not. If there is no SPL, then this is U-Boot proper. If
 * there is SPL but no TPL, the the first phase is SPL. If there is TPL, then
 * it is the first phase.
 *
 * @returns true if this is the first phase of U-Boot
 *
 */
static inline bool u_boot_first_phase(void)
{
	if (IS_ENABLED(CONFIG_TPL)) {
		if (IS_ENABLED(CONFIG_TPL_BUILD))
			return true;
	} else if (IS_ENABLED(CONFIG_SPL)) {
		if (IS_ENABLED(CONFIG_SPL_BUILD))
			return true;
	} else {
		return true;
	}

	return false;
}

enum u_boot_phase {
	PHASE_TPL,	/* Running in TPL */
	PHASE_SPL,	/* Running in SPL */
	PHASE_BOARD_F,	/* Running in U-Boot before relocation */
	PHASE_BOARD_R,	/* Running in U-Boot after relocation */
};

/**
 * spl_phase() - Find out the phase of U-Boot
 *
 * This can be used to avoid #ifdef logic and use if() instead.
 *
 * For example, to include code only in TPL, you might do:
 *
 *    #ifdef CONFIG_TPL_BUILD
 *    ...
 *    #endif
 *
 * but with this you can use:
 *
 *    if (spl_phase() == PHASE_TPL) {
 *       ...
 *    }
 *
 * To include code only in SPL, you might do:
 *
 *    #if defined(CONFIG_SPL_BUILD) && !defined(CONFIG_TPL_BUILD)
 *    ...
 *    #endif
 *
 * but with this you can use:
 *
 *    if (spl_phase() == PHASE_SPL) {
 *       ...
 *    }
 *
 * To include code only in U-Boot proper, you might do:
 *
 *    #ifndef CONFIG_SPL_BUILD
 *    ...
 *    #endif
 *
 * but with this you can use:
 *
 *    if (spl_phase() == PHASE_BOARD_F) {
 *       ...
 *    }
 *
 * @return U-Boot phase
 */
static inline enum u_boot_phase spl_phase(void)
{
#ifdef CONFIG_TPL_BUILD
	return PHASE_TPL;
#elif CONFIG_SPL_BUILD
	return PHASE_SPL;
#else
	DECLARE_GLOBAL_DATA_PTR;

	if (!(gd->flags & GD_FLG_RELOC))
		return PHASE_BOARD_F;
	else
		return PHASE_BOARD_R;
#endif
}

/* A string name for SPL or TPL */
#ifdef CONFIG_SPL_BUILD
# ifdef CONFIG_TPL_BUILD
#  define SPL_TPL_NAME	"TPL"
# else
#  define SPL_TPL_NAME	"SPL"
# endif
# define SPL_TPL_PROMPT	SPL_TPL_NAME ": "
#else
# define SPL_TPL_NAME	""
# define SPL_TPL_PROMPT	""
#endif

struct spl_image_info {
	const char *name;
	u8 os;
	uintptr_t load_addr;
	uintptr_t entry_point;
#if CONFIG_IS_ENABLED(LOAD_FIT) || CONFIG_IS_ENABLED(LOAD_FIT_FULL)
	void *fdt_addr;
#endif
	u32 boot_device;
	u32 size;
	u32 flags;
	void *arg;
#ifdef CONFIG_SPL_LEGACY_IMAGE_CRC_CHECK
	ulong dcrc_data;
	ulong dcrc_length;
	ulong dcrc;
#endif
};

/*
 * Information required to load data from a device
 *
 * @dev: Pointer to the device, e.g. struct mmc *
 * @priv: Private data for the device
 * @bl_len: Block length for reading in bytes
 * @filename: Name of the fit image file.
 * @read: Function to call to read from the device
 */
struct spl_load_info {
	void *dev;
	void *priv;
	int bl_len;
	const char *filename;
	ulong (*read)(struct spl_load_info *load, ulong sector, ulong count,
		      void *buf);
};

/*
 * We need to know the position of U-Boot in memory so we can jump to it. We
 * allow any U-Boot binary to be used (u-boot.bin, u-boot-nodtb.bin,
 * u-boot.img), hence the '_any'. These is no checking here that the correct
 * image is found. For example if u-boot.img is used we don't check that
 * spl_parse_image_header() can parse a valid header.
 *
 * Similarly for SPL, so that TPL can jump to SPL.
 */
binman_sym_extern(ulong, u_boot_any, image_pos);
binman_sym_extern(ulong, u_boot_any, size);
binman_sym_extern(ulong, spl, image_pos);
binman_sym_extern(ulong, spl, size);

/**
 * spl_get_image_pos() - get the image position of the next phase
 *
 * This returns the image position to use to load the next phase of U-Boot
 */
ulong spl_get_image_pos(void);

/**
 * spl_get_image_size() - get the size of the next phase
 *
 * This returns the size to use to load the next phase of U-Boot
 */
ulong spl_get_image_size(void);

/**
 * spl_load_simple_fit_skip_processing() - Hook to allow skipping the FIT
 *	image processing during spl_load_simple_fit().
 *
 * Return true to skip FIT processing, false to preserve the full code flow
 * of spl_load_simple_fit().
 */
bool spl_load_simple_fit_skip_processing(void);

/**
 * spl_load_simple_fit() - Loads a fit image from a device.
 * @spl_image:	Image description to set up
 * @info:	Structure containing the information required to load data.
 * @sector:	Sector number where FIT image is located in the device
 * @fdt:	Pointer to the copied FIT header.
 *
 * Reads the FIT image @sector in the device. Loads u-boot image to
 * specified load address and copies the dtb to end of u-boot image.
 * Returns 0 on success.
 */
int spl_load_simple_fit(struct spl_image_info *spl_image,
			struct spl_load_info *info, ulong sector, void *fdt);

#define SPL_COPY_PAYLOAD_ONLY	1
#define SPL_FIT_FOUND		2

/**
 * spl_load_imx_container() - Loads a imx container image from a device.
 * @spl_image:	Image description to set up
 * @info:	Structure containing the information required to load data.
 * @sector:	Sector number where container image is located in the device
 *
 * Reads the container image @sector in the device. Loads u-boot image to
 * specified load address.
 */
int spl_load_imx_container(struct spl_image_info *spl_image,
			   struct spl_load_info *info, ulong sector);

/* SPL common functions */
void preloader_console_init(void);
u32 spl_boot_device(void);
u32 spl_boot_mode(const u32 boot_device);
int spl_boot_partition(const u32 boot_device);
void spl_set_bd(void);

/**
 * spl_set_header_raw_uboot() - Set up a standard SPL image structure
 *
 * This sets up the given spl_image which the standard values obtained from
 * config options: CONFIG_SYS_MONITOR_LEN, CONFIG_SYS_UBOOT_START,
 * CONFIG_SYS_TEXT_BASE.
 *
 * @spl_image: Image description to set up
 */
void spl_set_header_raw_uboot(struct spl_image_info *spl_image);

/**
 * spl_parse_image_header() - parse the image header and set up info
 *
 * This parses the legacy image header information at @header and sets up
 * @spl_image according to what is found. If no image header is found, then
 * a raw image or bootz is assumed. If CONFIG_SPL_PANIC_ON_RAW_IMAGE is
 * enabled, then this causes a panic. If CONFIG_SPL_RAW_IMAGE_SUPPORT is not
 * enabled then U-Boot gives up. Otherwise U-Boot sets up the image using
 * spl_set_header_raw_uboot(), or possibly the bootz header.
 *
 * @spl_image: Image description to set up
 * @header image header to parse
 * @return 0 if a header was correctly parsed, -ve on error
 */
int spl_parse_image_header(struct spl_image_info *spl_image,
			   const struct image_header *header);

void spl_board_prepare_for_linux(void);
void spl_board_prepare_for_boot(void);
int spl_board_ubi_load_image(u32 boot_device);
int spl_board_boot_device(u32 boot_device);

/**
 * jump_to_image_linux() - Jump to a Linux kernel from SPL
 *
 * This jumps into a Linux kernel using the information in @spl_image.
 *
 * @spl_image: Image description to set up
 */
void __noreturn jump_to_image_linux(struct spl_image_info *spl_image);

/**
 * spl_start_uboot() - Check if SPL should start the kernel or U-Boot
 *
 * This is called by the various SPL loaders to determine whether the board
 * wants to load the kernel or U-Boot. This function should be provided by
 * the board.
 *
 * @return 0 if SPL should start the kernel, 1 if U-Boot must be started
 */
int spl_start_uboot(void);

/**
 * spl_display_print() - Display a board-specific message in SPL
 *
 * If CONFIG_SPL_DISPLAY_PRINT is enabled, U-Boot will call this function
 * immediately after displaying the SPL console banner ("U-Boot SPL ...").
 * This function should be provided by the board.
 */
void spl_display_print(void);

/**
 * struct spl_boot_device - Describes a boot device used by SPL
 *
 * @boot_device: A number indicating the BOOT_DEVICE type. There are various
 * BOOT_DEVICE... #defines and enums in U-Boot and they are not consistently
 * numbered.
 * @boot_device_name: Named boot device, or NULL if none.
 *
 * Note: Additional fields can be added here, bearing in mind that SPL is
 * size-sensitive and common fields will be present on all boards. This
 * struct can also be used to return additional information about the load
 * process if that becomes useful.
 */
struct spl_boot_device {
	uint boot_device;
	const char *boot_device_name;
};

/**
 * Holds information about a way of loading an SPL image
 *
 * @name: User-friendly name for this method (e.g. "MMC")
 * @boot_device: Boot device that this loader supports
 * @load_image: Function to call to load image
 */
struct spl_image_loader {
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
	const char *name;
#endif
	uint boot_device;
	/**
	 * load_image() - Load an SPL image
	 *
	 * @spl_image: place to put image information
	 * @bootdev: describes the boot device to load from
	 */
	int (*load_image)(struct spl_image_info *spl_image,
			  struct spl_boot_device *bootdev);
};

/* Declare an SPL image loader */
#define SPL_LOAD_IMAGE(__name)					\
	ll_entry_declare(struct spl_image_loader, __name, spl_image_loader)

/*
 * _priority is the priority of this method, 0 meaning it will be the top
 * choice for this device, 9 meaning it is the bottom choice.
 * _boot_device is the BOOT_DEVICE_... value
 * _method is the load_image function to call
 */
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
#define SPL_LOAD_IMAGE_METHOD(_name, _priority, _boot_device, _method) \
	SPL_LOAD_IMAGE(_boot_device ## _priority ## _method) = { \
		.name = _name, \
		.boot_device = _boot_device, \
		.load_image = _method, \
	}
#else
#define SPL_LOAD_IMAGE_METHOD(_name, _priority, _boot_device, _method) \
	SPL_LOAD_IMAGE(_boot_device ## _priority ## _method) = { \
		.boot_device = _boot_device, \
		.load_image = _method, \
	}
#endif

/* SPL FAT image functions */
int spl_load_image_fat(struct spl_image_info *spl_image,
		       struct blk_desc *block_dev, int partition,
		       const char *filename);
int spl_load_image_fat_os(struct spl_image_info *spl_image,
			  struct blk_desc *block_dev, int partition);

void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image);

/* SPL EXT image functions */
int spl_load_image_ext(struct spl_image_info *spl_image,
		       struct blk_desc *block_dev, int partition,
		       const char *filename);
int spl_load_image_ext_os(struct spl_image_info *spl_image,
			  struct blk_desc *block_dev, int partition);

/**
 * spl_early_init() - Set up device tree and driver model in SPL if enabled
 *
 * Call this function in board_init_f() if you want to use device tree and
 * driver model early, before board_init_r() is called.
 *
 * If this is not called, then driver model will be inactive in SPL's
 * board_init_f(), and no device tree will be available.
 */
int spl_early_init(void);

/**
 * spl_init() - Set up device tree and driver model in SPL if enabled
 *
 * You can optionally call spl_early_init(), then optionally call spl_init().
 * This function will be called from board_init_r() if not called earlier.
 *
 * Both spl_early_init() and spl_init() perform a similar function except that
 * the latter will not set up the malloc() area if
 * CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN is enabled, since it is assumed to
 * already be done by a calll to spl_relocate_stack_gd() before board_init_r()
 * is reached.
 *
 * This function will be called from board_init_r() if not called earlier.
 *
 * If this is not called, then driver model will be inactive in SPL's
 * board_init_f(), and no device tree will be available.
 */
int spl_init(void);

#ifdef CONFIG_SPL_BOARD_INIT
void spl_board_init(void);
#endif

/**
 * spl_was_boot_source() - check if U-Boot booted from SPL
 *
 * This will normally be true, but if U-Boot jumps to second U-Boot, it will
 * be false. This should be implemented by board-specific code.
 *
 * @return true if U-Boot booted from SPL, else false
 */
bool spl_was_boot_source(void);

/**
 * spl_dfu_cmd- run dfu command with chosen mmc device interface
 * @param usb_index - usb controller number
 * @param mmc_dev -  mmc device nubmer
 *
 * @return 0 on success, otherwise error code
 */
int spl_dfu_cmd(int usbctrl, char *dfu_alt_info, char *interface, char *devstr);

int spl_mmc_load_image(struct spl_image_info *spl_image,
		       struct spl_boot_device *bootdev);

/**
 * spl_mmc_load() - Load an image file from MMC/SD media
 *
 * @param spl_image	Image data filled in by loading process
 * @param bootdev	Describes which device to load from
 * @param filename	Name of file to load (in FS mode)
 * @param raw_part	Partition to load from (in RAW mode)
 * @param raw_sect	Sector to load from (in RAW mode)
 *
 * @return 0 on success, otherwise error code
 */
int spl_mmc_load(struct spl_image_info *spl_image,
		 struct spl_boot_device *bootdev,
		 const char *filename,
		 int raw_part,
		 unsigned long raw_sect);

int spl_ymodem_load_image(struct spl_image_info *spl_image,
			  struct spl_boot_device *bootdev);

/**
 * spl_invoke_atf - boot using an ARM trusted firmware image
 */
void spl_invoke_atf(struct spl_image_info *spl_image);

/**
 * bl2_plat_get_bl31_params() - prepare params for bl31.
 * @bl32_entry	address of BL32 executable (secure)
 * @bl33_entry	address of BL33 executable (non secure)
 * @fdt_addr	address of Flat Device Tree
 *
 * This function assigns a pointer to the memory that the platform has kept
 * aside to pass platform specific and trusted firmware related information
 * to BL31. This memory is allocated by allocating memory to
 * bl2_to_bl31_params_mem structure which is a superset of all the
 * structure whose information is passed to BL31
 * NOTE: This function should be called only once and should be done
 * before generating params to BL31
 *
 * @return bl31 params structure pointer
 */
struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry,
					     uintptr_t bl33_entry,
					     uintptr_t fdt_addr);

/**
 * spl_optee_entry - entry function for optee
 *
 * args defind in op-tee project
 * https://github.com/OP-TEE/optee_os/
 * core/arch/arm/kernel/generic_entry_a32.S
 * @arg0: pagestore
 * @arg1: (ARMv7 standard bootarg #1)
 * @arg2: device tree address, (ARMv7 standard bootarg #2)
 * @arg3: non-secure entry address (ARMv7 bootarg #0)
 */
void spl_optee_entry(void *arg0, void *arg1, void *arg2, void *arg3);

/**
 * spl_invoke_opensbi - boot using a RISC-V OpenSBI image
 */
void spl_invoke_opensbi(struct spl_image_info *spl_image);

/**
 * board_return_to_bootrom - allow for boards to continue with the boot ROM
 *
 * If a board (e.g. the Rockchip RK3368 boards) provide some
 * supporting functionality for SPL in their boot ROM and the SPL
 * stage wants to return to the ROM code to continue booting, boards
 * can implement 'board_return_to_bootrom'.
 */
int board_return_to_bootrom(struct spl_image_info *spl_image,
			    struct spl_boot_device *bootdev);

/**
 * board_spl_fit_post_load - allow process images after loading finished
 *
 */
void board_spl_fit_post_load(ulong load_addr, size_t length);

/**
 * board_spl_fit_size_align - specific size align before processing payload
 *
 */
ulong board_spl_fit_size_align(ulong size);

/**
 * spl_perform_fixups() - arch/board-specific callback before processing
 *                        the boot-payload
 */
void spl_perform_fixups(struct spl_image_info *spl_image);

/*
 * spl_get_load_buffer() - get buffer for loading partial image data
 *
 * Returns memory area which can be populated by partial image data,
 * ie. uImage or fitImage header.
 */
struct image_header *spl_get_load_buffer(ssize_t offset, size_t size);

#endif