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
|
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2025 Linaro Ltd.
* Author: Sam Protsenko <[email protected]>
*
* Routines for checking current boot device.
*/
#include <linux/arm-smccc.h>
#include <vsprintf.h>
#include "bootdev.h"
/* Flag from BL2 bootloader in RAM */
#define BL2_TAG_ADDR 0x80000000 /* DRAM base */
#define BL2_TAG 0xabcdef
/* Boot device info location in iRAM (only accessible from EL3) */
#define IRAM_BASE 0x02020000
#define BOOTDEVICE_INFO_ADDR (IRAM_BASE + 0x64)
/* SMC call for getting boot device information from EL3 monitor */
#define SMC_CMD_CHECK_SECOND_BOOT -233
/* Boot device constants for the encoded boot device info value */
#define BD_NO_DEVICE 0x0
#define BD_UFS 0x1
#define BD_EMMC 0x2
#define BD_ERROR 0x3
#define BD_USB 0x4
#define BD_SDMMC 0x5
#define BD_UFS_CARD 0x6
#define BD_SPI 0x7
/* If BL2 bootloader wasn't executed, it means U-Boot is running via JTAG */
static bool bootdev_is_jtag_session(void)
{
u32 bl2_tag_val = *(u32 *)BL2_TAG_ADDR;
return bl2_tag_val != BL2_TAG;
}
/* Obtain boot device information encoded in 32-bit value */
static u32 bootdev_get_info(void)
{
u32 info;
/*
* On regular boot U-Boot is executed by BL2 bootloader, and is running
* in EL1 mode, so the boot device information has to be obtained via
* SMC call from EL3 software (EL3 monitor), which can read that info
* from the protected iRAM memory. If U-Boot is running via TRACE32 JTAG
* (in EL3 mode), read the boot device info directly from iRAM, as EL3
* software might not be available.
*/
if (bootdev_is_jtag_session()) {
info = *(u32 *)BOOTDEVICE_INFO_ADDR;
} else {
struct arm_smccc_res res;
arm_smccc_smc(SMC_CMD_CHECK_SECOND_BOOT, 0, 0, 0, 0, 0, 0, 0,
&res);
info = (u32)res.a2;
}
return info;
}
enum bootdev bootdev_get_current(void)
{
u32 info, magic, order, dev;
info = bootdev_get_info();
magic = info >> 24;
order = info & 0xf;
dev = (info >> (4 * order)) & 0xf;
if (magic != 0xcb)
panic("Abnormal boot");
switch (dev) {
case BD_UFS:
return BOOTDEV_UFS;
case BD_EMMC:
return BOOTDEV_EMMC;
case BD_USB:
return BOOTDEV_USB;
case BD_SDMMC:
return BOOTDEV_SD;
default:
return BOOTDEV_ERROR;
}
return BOOTDEV_ERROR;
}
bool bootdev_is_usb(void)
{
return bootdev_get_current() == BOOTDEV_USB;
}
|