board: samsung: e850-96: Add routines for checking boot dev

Implement functionality to check the current boot device (a device where
the SoC ROM code is loading the bootloaders from). The boot device order
can be changed using the SW1 DIP switch on the E850-96 board (which
controls XOM SoC lines), as stated in [1].

The boot device information is requested from EL3 software using the
corresponding SMC call, which in turn reads it from iRAM memory, which
was written by the ROM code. New routines decode that data and allow the
user to check the current boot device, boot order, etc. That API can be
used further to implement different code flows depending on the current
boot device, e.g.:

  - on eMMC boot: obtain the firmware binaries from eMMC
  - on USB boot: download the firmware over USB instead

No functional change; this patch only adds new functionality but it's
not used yet.

[1] doc/board/samsung/e850-96.rst

Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
This commit is contained in:
Sam Protsenko
2025-11-18 17:21:15 -06:00
committed by Minkyu Kang
parent f737f0675f
commit 1d9aafa751
3 changed files with 123 additions and 1 deletions

View File

@@ -3,4 +3,4 @@
# Copyright (C) 2024, Linaro Limited
# Sam Protsenko <semen.protsenko@linaro.org>
obj-y := e850-96.o fw.o acpm.o pmic.o
obj-y := e850-96.o fw.o acpm.o pmic.o bootdev.o

View File

@@ -0,0 +1,99 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2025 Linaro Ltd.
* Author: Sam Protsenko <semen.protsenko@linaro.org>
*
* 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;
}

View File

@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2025 Linaro Ltd.
* Sam Protsenko <semen.protsenko@linaro.org>
*/
#ifndef __E850_96_BOOTDEV_H
#define __E850_96_BOOTDEV_H
#include <stdbool.h>
enum bootdev {
BOOTDEV_ERROR,
BOOTDEV_SD,
BOOTDEV_EMMC,
BOOTDEV_USB,
BOOTDEV_UFS,
};
enum bootdev bootdev_get_current(void);
bool bootdev_is_usb(void);
#endif /* __E850_96_BOOTDEV_H */