~funderscore blog cgit wiki get in touch
aboutsummaryrefslogtreecommitdiff
blob: 92bcaa90a4afe4b3d51217d27b7173feeef74b03 (plain)
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
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * (C) Copyright 2012
 * Texas Instruments, <www.ti.com>
 */
#ifndef	_SPL_H_
#define	_SPL_H_

#include <binman_sym.h>
#include <linker_lists.h>

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

struct blk_desc;
struct legacy_img_hdr;

/* 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

struct blk_desc;
struct legacy_img_hdr;
struct spl_boot_device;
enum boot_device;

/*
 * 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_NONE,	/* Invalid phase, signifying before U-Boot */
	PHASE_TPL,	/* Running in TPL */
	PHASE_VPL,	/* Running in VPL */
	PHASE_SPL,	/* Running in SPL */
	PHASE_BOARD_F,	/* Running in U-Boot before relocation */
	PHASE_BOARD_R,	/* Running in U-Boot after relocation */

	PHASE_COUNT,
};

/**
 * 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 defined(CONFIG_VPL_BUILD)
	return PHASE_VPL;
#elif defined(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
}

/**
 * spl_prev_phase() - Figure out the previous U-Boot phase
 *
 * Return: the previous phase from this one, e.g. if called in SPL this returns
 *	PHASE_TPL, if TPL is enabled
 */
static inline enum u_boot_phase spl_prev_phase(void)
{
#ifdef CONFIG_TPL_BUILD
	return PHASE_NONE;
#elif defined(CONFIG_VPL_BUILD)
	return PHASE_TPL;	/* VPL requires TPL */
#elif defined(CONFIG_SPL_BUILD)
	return IS_ENABLED(CONFIG_VPL) ? PHASE_VPL :
		IS_ENABLED(CONFIG_TPL) ? PHASE_TPL :
		PHASE_NONE;
#else
	return IS_ENABLED(CONFIG_SPL) ? PHASE_SPL :
		PHASE_NONE;
#endif
}

/**
 * spl_next_phase() - Figure out the next U-Boot phase
 *
 * Return: the next phase from this one, e.g. if called in TPL this returns
 *	PHASE_SPL
 */
static inline enum u_boot_phase spl_next_phase(void)
{
#ifdef CONFIG_TPL_BUILD
	return IS_ENABLED(CONFIG_VPL) ? PHASE_VPL : PHASE_SPL;
#elif defined(CONFIG_VPL_BUILD)
	return PHASE_SPL;
#else
	return PHASE_BOARD_F;
#endif
}

/**
 * spl_phase_name() - Get the name of the current phase
 *
 * Return: phase name
 */
static inline const char *spl_phase_name(enum u_boot_phase phase)
{
	switch (phase) {
	case PHASE_TPL:
		return "TPL";
	case PHASE_VPL:
		return "VPL";
	case PHASE_SPL:
		return "SPL";
	case PHASE_BOARD_F:
	case PHASE_BOARD_R:
		return "U-Boot";
	default:
		return "phase?";
	}
}

/**
 * spl_phase_prefix() - Get the prefix  of the current phase
 *
 * @phase: Phase to look up
 * Return: phase prefix ("spl", "tpl", etc.)
 */
static inline const char *spl_phase_prefix(enum u_boot_phase phase)
{
	switch (phase) {
	case PHASE_TPL:
		return "tpl";
	case PHASE_VPL:
		return "vpl";
	case PHASE_SPL:
		return "spl";
	case PHASE_BOARD_F:
	case PHASE_BOARD_R:
		return "";
	default:
		return "phase?";
	}
}

/* A string name for SPL or TPL */
#ifdef CONFIG_SPL_BUILD
# ifdef CONFIG_TPL_BUILD
#  define SPL_TPL_NAME	"TPL"
# elif defined(CONFIG_VPL_BUILD)
#  define SPL_TPL_NAME	"VPL"
# else
#  define SPL_TPL_NAME	"SPL"
# endif
# define SPL_TPL_PROMPT	SPL_TPL_NAME ": "
#else
# define SPL_TPL_NAME	""
# define SPL_TPL_PROMPT	""
#endif

/**
 * enum spl_sandbox_flags - flags for sandbox's use of spl_image_info->flags
 *
 * @SPL_SANDBOXF_ARG_IS_FNAME: arg is the filename to jump to (default)
 * @SPL_SANDBOXF_ARG_IS_BUF: arg is the containing image to jump to, @offset is
 *	the start offset within the image, @size is the size of the image
 */
enum spl_sandbox_flags {
	SPL_SANDBOXF_ARG_IS_FNAME = 0,
	SPL_SANDBOXF_ARG_IS_BUF,
};

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 offset;
	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;
	/**
	 * read() - Read from device
	 *
	 * @load: Information about the load state
	 * @sector: Sector number to read from (each @load->bl_len bytes)
	 * @count: Number of sectors to read
	 * @buf: Buffer to read into
	 * @return number of sectors read, 0 on error
	 */
	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, u_boot_spl_any, image_pos);
binman_sym_extern(ulong, u_boot_spl_any, size);
binman_sym_extern(ulong, u_boot_vpl_any, image_pos);
binman_sym_extern(ulong, u_boot_vpl_any, 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_get_image_text_base() - get the text base of the next phase
 *
 * This returns the address that the next stage is linked to run at, i.e.
 * CONFIG_SPL_TEXT_BASE or CONFIG_TEXT_BASE
 *
 * Return: text-base address
 */
ulong spl_get_image_text_base(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_fix_load() - Hook to make fixes
 * after fit image header is loaded
 *
 * Returns pointer to fit
 */
void *spl_load_simple_fit_fix_load(const void *fit);

/**
 * 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_legacy_img() - Loads a legacy image from a device.
 * @spl_image:	Image description to set up
 * @load:	Structure containing the information required to load data.
 * @offset:	Pointer to image
 * @hdr:	Pointer to image header
 *
 * Reads an legacy image from the device. Loads u-boot image to
 * specified load address.
 * Returns 0 on success.
 */
int spl_load_legacy_img(struct spl_image_info *spl_image,
			struct spl_boot_device *bootdev,
			struct spl_load_info *load, ulong offset,
			struct legacy_img_hdr *hdr);


/**
 * 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);

/**
 * spl_spi_boot_bus() - Lookup function for the SPI boot bus source.
 *
 * This function returns the SF bus to load from.
 * If not overridden, it is weakly defined in common/spl/spl_spi.c.
 */
u32 spl_spi_boot_bus(void);

/**
 * spl_spi_boot_cs() - Lookup function for the SPI boot CS source.
 *
 * This function returns the SF CS to load from.
 * If not overridden, it is weakly defined in common/spl/spl_spi.c.
 */
u32 spl_spi_boot_cs(void);

/**
 * spl_mmc_boot_mode() - Lookup function for the mode of an MMC boot source.
 * @boot_device:	ID of the device which the MMC driver wants to read
 *			from.  Common values are e.g. BOOT_DEVICE_MMC1,
 *			BOOT_DEVICE_MMC2, BOOT_DEVICE_MMC2_2.
 *
 * This function should return one of MMCSD_MODE_FS, MMCSD_MODE_EMMCBOOT, or
 * MMCSD_MODE_RAW for each MMC boot source which is defined for the target.  The
 * boot_device parameter tells which device the MMC driver is interested in.
 *
 * If not overridden, it is weakly defined in common/spl/spl_mmc.c.
 *
 * Note:  It is important to use the boot_device parameter instead of e.g.
 * spl_boot_device() as U-Boot is not always loaded from the same device as SPL.
 */
u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device);

/**
 * spl_mmc_boot_partition() - MMC partition to load U-Boot from.
 * @boot_device:	ID of the device which the MMC driver wants to load
 *			U-Boot from.
 *
 * This function should return the partition number which the SPL
 * should load U-Boot from (on the given boot_device) when
 * CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION is set.
 *
 * If not overridden, it is weakly defined in common/spl/spl_mmc.c.
 */
int spl_mmc_boot_partition(const u32 boot_device);

struct mmc;
/**
 * default_spl_mmc_emmc_boot_partition() - eMMC boot partition to load U-Boot from.
 * mmc:			Pointer for the mmc device structure
 *
 * This function should return the eMMC boot partition number which
 * the SPL should load U-Boot from (on the given boot_device).
 */
int default_spl_mmc_emmc_boot_partition(struct mmc *mmc);

/**
 * spl_mmc_emmc_boot_partition() - eMMC boot partition to load U-Boot from.
 * mmc:			Pointer for the mmc device structure
 *
 * This function should return the eMMC boot partition number which
 * the SPL should load U-Boot from (on the given boot_device).
 *
 * If not overridden, it is weakly defined in common/spl/spl_mmc.c
 * and calls default_spl_mmc_emmc_boot_partition();
 */
int spl_mmc_emmc_boot_partition(struct mmc *mmc);

void spl_set_bd(void);

/**
 * spl_mmc_get_uboot_raw_sector() - Provide raw sector of the start of U-Boot
 *
 * This is a weak function which by default will provide the raw sector that is
 * where the start of the U-Boot image has been written to.
 *
 * @mmc: struct mmc that describes the devie where U-Boot resides
 * @raw_sect: The raw sector number where U-Boot is by default.
 * Return: The raw sector location that U-Boot resides at
 */
unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc,
					   unsigned long raw_sect);

/**
 * 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, CFG_SYS_UBOOT_START,
 * CONFIG_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 spl_boot_device *bootdev,
			   const struct legacy_img_hdr *header);

void spl_board_prepare_for_linux(void);

/**
 * spl_board_prepare_for_optee() - Prepare board for an OPTEE payload
 *
 * Prepares the board for booting an OP-TEE payload. Initialization is platform
 * specific, and may include configuring the TrustZone memory, and other
 * initialization steps required by OP-TEE.
 * Note that @fdt is not used directly by OP-TEE. OP-TEE passes this @fdt to
 * its normal world target. This target is not guaranteed to be u-boot, so @fdt
 * changes that would normally be done by u-boot should be done in this step.
 *
 * @fdt: Devicetree that will be passed on, or NULL
 */
void spl_board_prepare_for_optee(void *fdt);
void spl_board_prepare_for_boot(void);
int spl_board_ubi_load_image(u32 boot_device);
int spl_board_boot_device(enum boot_device boot_dev_spl);

/**
 * spl_board_loader_name() - Return a name for the loader
 *
 * This is a weak function which might be overridden by the board code. With
 * that a board specific value for the device where the U-Boot will be loaded
 * from can be set. By default it returns NULL.
 *
 * @boot_device:	ID of the device which SPL wants to load U-Boot from.
 */
const char *spl_board_loader_name(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);

/**
 * jump_to_image_optee() - Jump to OP-TEE OS from SPL
 *
 * This jumps into OP-TEE OS using the information in @spl_image.
 *
 * @spl_image: Image description to set up
 */
void __noreturn jump_to_image_optee(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);
};

/* Helper function for accessing the name */
static inline const char *spl_loader_name(const struct spl_image_loader *loader)
{
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
	const char *name;
	name = spl_board_loader_name(loader->boot_device);
	return name ?: loader->name;
#else
	return NULL;
#endif
}

/* 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 spl_boot_device *bootdev,
		       struct blk_desc *block_dev, int partition,
		       const char *filename);
int spl_load_image_fat_os(struct spl_image_info *spl_image,
			  struct spl_boot_device *bootdev,
			  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 spl_boot_device *bootdev,
		       struct blk_desc *block_dev, int partition,
		       const char *filename);
int spl_load_image_ext_os(struct spl_image_info *spl_image,
			  struct spl_boot_device *bootdev,
			  struct blk_desc *block_dev, int partition);
int spl_blk_load_image(struct spl_image_info *spl_image,
		       struct spl_boot_device *bootdev,
		       enum uclass_id uclass_id, int devnum, int partnum);

/**
 * 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);

/**
 * spl_usb_load() - Load an image file from USB mass storage
 *
 * @param spl_image	Image data filled in by loading process
 * @param bootdev	Describes which device to load from
 * @param raw_part	Fat partition to load from
 * @param filename	Name of file to load
 *
 * Return: 0 on success, otherwise error code
 */
int spl_usb_load(struct spl_image_info *spl_image,
		 struct spl_boot_device *bootdev,
		 int partition, const char *filename);

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() - return 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 is a weak function which might be overridden by the board code. By
 * default it will just call bl2_plat_get_bl31_params_default().
 *
 * If you just want to manipulate or add some parameters, you can override
 * this function, call bl2_plat_get_bl31_params_default and operate on the
 * returned bl31 params.
 *
 * 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);

/**
 * bl2_plat_get_bl31_params_default() - 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 is the default implementation of bl2_plat_get_bl31_params(). It 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: The memory is statically allocated, thus this function should be
 * called only once. All subsequent calls will overwrite any changes.
 *
 * Return: bl31 params structure pointer
 */
struct bl31_params *bl2_plat_get_bl31_params_default(uintptr_t bl32_entry,
						     uintptr_t bl33_entry,
						     uintptr_t fdt_addr);

/**
 * bl2_plat_get_bl31_params_v2() - return 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 does the same as bl2_plat_get_bl31_params() except that is is
 * used for the new LOAD_IMAGE_V2 option, which uses a slightly different
 * method to pass the parameters.
 *
 * Return: bl31 params structure pointer
 */
struct bl_params *bl2_plat_get_bl31_params_v2(uintptr_t bl32_entry,
					      uintptr_t bl33_entry,
					      uintptr_t fdt_addr);

/**
 * bl2_plat_get_bl31_params_v2_default() - 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 is the default implementation of bl2_plat_get_bl31_params_v2(). It
 * prepares the linked list of the bl31 params, populates the image types and
 * set the entry points for bl32 and bl33 (if available).
 *
 * NOTE: The memory is statically allocated, thus this function should be
 * called only once. All subsequent calls will overwrite any changes.
 *
 * Return: bl31 params structure pointer
 */
struct bl_params *bl2_plat_get_bl31_params_v2_default(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 __noreturn 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_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 legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size);

void board_boot_order(u32 *spl_boot_list);
void spl_save_restore_data(void);
#endif