summaryrefslogtreecommitdiff
path: root/board
diff options
context:
space:
mode:
authorKaustabh Chakraborty <[email protected]>2025-10-24 22:58:27 +0530
committerMinkyu Kang <[email protected]>2025-12-02 13:38:27 +0900
commited9ba442ee1f9aea1ab92b10e56c8ac710a770cf (patch)
treedf1ef0632aa37ded3983d00ef949a111f8dcc61c /board
parentff3b4e9936a720870decd6ddb0e77c7b5d464d5d (diff)
board: samsung: add support for Samsung Exynos mobile device boards
Add support for a generic platform which intends to support multiple boards powered by ARMv8 Samsung Exynos SoCs. Some important features include: * Fastboot: This is present to provide an open alternative to Samsung's proprietary Odin protocol. The board file configures certain features for fastboot, such as a dynamically allocated fastboot buffer, and standardized (lowercase) partition aliases. * EFI: Kernel image can be loaded from an EFI partition. This adopts a standard booting process, which multiple OS distributions can rely on. Signed-off-by: Kaustabh Chakraborty <[email protected]> Signed-off-by: Minkyu Kang <[email protected]>
Diffstat (limited to 'board')
-rw-r--r--board/samsung/exynos-mobile/Kconfig18
-rw-r--r--board/samsung/exynos-mobile/MAINTAINERS6
-rw-r--r--board/samsung/exynos-mobile/Makefile5
-rw-r--r--board/samsung/exynos-mobile/exynos-mobile.c287
-rw-r--r--board/samsung/exynos-mobile/exynos-mobile.env18
5 files changed, 334 insertions, 0 deletions
diff --git a/board/samsung/exynos-mobile/Kconfig b/board/samsung/exynos-mobile/Kconfig
new file mode 100644
index 00000000000..ed7d16b8c6b
--- /dev/null
+++ b/board/samsung/exynos-mobile/Kconfig
@@ -0,0 +1,18 @@
+if TARGET_EXYNOS_MOBILE
+
+config ENV_SOURCE_FILE
+ default "exynos-mobile"
+
+config LNX_KRNL_IMG_TEXT_OFFSET_BASE
+ default TEXT_BASE
+
+config SYS_BOARD
+ default "exynos-mobile"
+
+config SYS_CONFIG_NAME
+ default "exynos-mobile"
+
+config SYS_VENDOR
+ default "samsung"
+
+endif # TARGET_EXYNOS_MOBILE
diff --git a/board/samsung/exynos-mobile/MAINTAINERS b/board/samsung/exynos-mobile/MAINTAINERS
new file mode 100644
index 00000000000..11fea212fb1
--- /dev/null
+++ b/board/samsung/exynos-mobile/MAINTAINERS
@@ -0,0 +1,6 @@
+Exynos Generic Boards (for mobile devices)
+M: Kaustabh Chakraborty <[email protected]>
+S: Maintained
+F: board/samsung/exynos-mobile/
+F: configs/exynos-mobile_defconfig
+F: include/configs/exynos-mobile.h
diff --git a/board/samsung/exynos-mobile/Makefile b/board/samsung/exynos-mobile/Makefile
new file mode 100644
index 00000000000..e049ed217c1
--- /dev/null
+++ b/board/samsung/exynos-mobile/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2025 Kaustabh Chakraborty <[email protected]>
+
+obj-y := exynos-mobile.o
diff --git a/board/samsung/exynos-mobile/exynos-mobile.c b/board/samsung/exynos-mobile/exynos-mobile.c
new file mode 100644
index 00000000000..c16281dbc36
--- /dev/null
+++ b/board/samsung/exynos-mobile/exynos-mobile.c
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Samsung Exynos Generic Board Source (for mobile devices)
+ *
+ * Copyright (c) 2025 Kaustabh Chakraborty <[email protected]>
+ */
+
+#include <asm/armv8/mmu.h>
+#include <blk.h>
+#include <bootflow.h>
+#include <ctype.h>
+#include <dm/ofnode.h>
+#include <env.h>
+#include <errno.h>
+#include <init.h>
+#include <linux/sizes.h>
+#include <lmb.h>
+#include <part.h>
+#include <stdbool.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define lmb_alloc(size, addr) \
+ lmb_alloc_mem(LMB_MEM_ALLOC_ANY, SZ_2M, addr, size, LMB_NONE)
+
+struct exynos_board_info {
+ const char *name;
+ const char *chip;
+ const u64 *const dram_bank_bases;
+
+ char serial[64];
+
+ int (*const match)(struct exynos_board_info *);
+ const char *match_model;
+ const u8 match_max_rev;
+};
+
+/*
+ * The memory mapping includes all DRAM banks, along with the
+ * peripheral block, and a sentinel at the end. This is filled in
+ * dynamically.
+ */
+static struct mm_region exynos_mem_map[CONFIG_NR_DRAM_BANKS + 2] = {
+ {
+ /* Peripheral MMIO block */
+ .virt = 0x10000000UL,
+ .phys = 0x10000000UL,
+ .size = 0x10000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN,
+ },
+};
+
+struct mm_region *mem_map = exynos_mem_map;
+
+/*
+ * This array is used for matching the models and revisions with the
+ * devicetree used by U-Boot. This allows a single U-Boot to work on
+ * multiple devices.
+ *
+ * Entries are kept in lexicographical order of board SoCs, followed by
+ * board names.
+ */
+static struct exynos_board_info exynos_board_info_match[] = {
+};
+
+static void exynos_parse_dram_banks(const struct exynos_board_info *board_info,
+ const void *fdt_base)
+{
+ u64 mem_addr, mem_size = 0;
+ u32 na, ns, i, j;
+ int offset;
+
+ if (fdt_check_header(fdt_base) < 0)
+ return;
+
+ /* #address-cells and #size-cells as defined in the fdt root. */
+ na = fdt_address_cells(fdt_base, 0);
+ ns = fdt_size_cells(fdt_base, 0);
+
+ fdt_for_each_subnode(offset, fdt_base, 0) {
+ if (strncmp(fdt_get_name(fdt_base, offset, NULL), "memory", 6))
+ continue;
+
+ for (i = 0; ; i++) {
+ mem_addr = fdtdec_get_addr_size_fixed(fdt_base, offset,
+ "reg", i, na, ns,
+ &mem_size, false);
+ if (mem_addr == FDT_ADDR_T_NONE)
+ break;
+
+ if (!mem_size)
+ continue;
+
+ for (j = 0; j < CONFIG_NR_DRAM_BANKS; j++) {
+ if (board_info->dram_bank_bases[j] != mem_addr)
+ continue;
+
+ mem_map[j + 1].phys = mem_addr;
+ mem_map[j + 1].virt = mem_addr;
+ mem_map[j + 1].size = mem_size;
+ mem_map[j + 1].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE;
+ break;
+ }
+ }
+ }
+}
+
+static int exynos_fastboot_setup(void)
+{
+ struct blk_desc *blk_dev;
+ struct disk_partition info = {0};
+ char buf[128];
+ phys_addr_t addr;
+ int offset, i, j;
+
+ /* Allocate and define buffer address for fastboot interface. */
+ if (lmb_alloc(CONFIG_FASTBOOT_BUF_SIZE, &addr)) {
+ log_err("%s: failed to allocate fastboot buffer\n", __func__);
+ return -ENOMEM;
+ }
+ env_set_hex("fastboot_addr_r", addr);
+
+ blk_dev = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
+ if (!blk_dev) {
+ log_err("%s: required mmc device not available\n", __func__);
+ return -ENODEV;
+ }
+
+ strcpy(buf, "fastboot_partition_alias_");
+ offset = strlen(buf);
+
+ for (i = 1; i < CONFIG_EFI_PARTITION_ENTRIES_NUMBERS; i++) {
+ if (part_get_info(blk_dev, i, &info))
+ continue;
+
+ /*
+ * The partition name must be lowercase (stored in buf[]),
+ * as is expected in all fastboot partitions ...
+ */
+ strlcpy(buf + offset, info.name, sizeof(buf) - offset);
+ for (j = offset; buf[j]; j++)
+ buf[j] = tolower(buf[j]);
+ if (!strcmp(buf + offset, info.name))
+ continue;
+ /*
+ * ... However, if that isn't the case, a fastboot
+ * partition alias must be defined to establish it.
+ */
+ env_set(buf, info.name);
+ }
+
+ return 0;
+}
+
+int board_fit_config_name_match(const char *name)
+{
+ struct exynos_board_info *board_info;
+ char buf[128];
+ unsigned int i;
+ int ret;
+
+ /*
+ * Iterate over exynos_board_info_match[] to select the
+ * appropriate board info struct. If not found, exit.
+ */
+ for (i = 0; i < ARRAY_SIZE(exynos_board_info_match); i++) {
+ board_info = exynos_board_info_match + i;
+ snprintf(buf, sizeof(buf), "%s-%s", board_info->chip,
+ board_info->name);
+
+ if (!strcmp(name, buf))
+ break;
+ }
+ if (i == ARRAY_SIZE(exynos_board_info_match))
+ return -1;
+
+ /*
+ * Execute match logic for the target board. This is separated
+ * as the process may be different for multiple boards.
+ */
+ ret = board_info->match(board_info);
+ if (ret)
+ return ret;
+
+ /*
+ * Store the correct board info struct in gd->board_type to
+ * allow other functions to access it.
+ */
+ gd->board_type = (ulong)board_info;
+ log_debug("%s: device detected: %s\n", __func__, name);
+
+ return 0;
+}
+
+int timer_init(void)
+{
+ ofnode timer_node;
+
+ /*
+ * In a lot of Exynos devices, the previous bootloader does not
+ * set CNTFRQ_EL0 properly. However, the timer node in
+ * devicetree has the correct frequency, use that instead.
+ */
+ timer_node = ofnode_by_compatible(ofnode_null(), "arm,armv8-timer");
+ gd->arch.timer_rate_hz = ofnode_read_u32_default(timer_node,
+ "clock-frequency", 0);
+
+ return 0;
+}
+
+int board_early_init_f(void)
+{
+ const struct exynos_board_info *board_info;
+
+ if (!gd->board_type)
+ return -ENODATA;
+ board_info = (const struct exynos_board_info *)gd->board_type;
+
+ exynos_parse_dram_banks(board_info, gd->fdt_blob);
+ /*
+ * Some devices have multiple variants based on the amount of
+ * memory and internal storage. The lowest bank base has been
+ * observed to have the same memory range in all board variants.
+ * For variants with more memory, the previous bootloader should
+ * overlay the devicetree with the required extra memory ranges.
+ */
+ exynos_parse_dram_banks(board_info, (const void *)get_prev_bl_fdt_addr());
+
+ return 0;
+}
+
+int dram_init(void)
+{
+ unsigned int i;
+
+ /* Select the largest RAM bank for U-Boot. */
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ if (gd->ram_size < mem_map[i + 1].size) {
+ gd->ram_base = mem_map[i + 1].phys;
+ gd->ram_size = mem_map[i + 1].size;
+ }
+ }
+
+ return 0;
+}
+
+int dram_init_banksize(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ gd->bd->bi_dram[i].start = mem_map[i + 1].phys;
+ gd->bd->bi_dram[i].size = mem_map[i + 1].size;
+ }
+
+ return 0;
+}
+
+int board_init(void)
+{
+ return 0;
+}
+
+int misc_init_r(void)
+{
+ const struct exynos_board_info *board_info;
+ char buf[128];
+
+ if (!gd->board_type)
+ return -ENODATA;
+ board_info = (const struct exynos_board_info *)gd->board_type;
+
+ env_set("platform", board_info->chip);
+ env_set("board", board_info->name);
+
+ if (strlen(board_info->serial))
+ env_set("serial#", board_info->serial);
+
+ /* EFI booting requires the path to correct dtb, specify it here. */
+ snprintf(buf, sizeof(buf), "exynos/%s-%s.dtb", board_info->chip,
+ board_info->name);
+ env_set("fdtfile", buf);
+
+ return exynos_fastboot_setup();
+}
diff --git a/board/samsung/exynos-mobile/exynos-mobile.env b/board/samsung/exynos-mobile/exynos-mobile.env
new file mode 100644
index 00000000000..aa2e89afbac
--- /dev/null
+++ b/board/samsung/exynos-mobile/exynos-mobile.env
@@ -0,0 +1,18 @@
+stdin=serial,button-kbd
+stdout=serial,vidconsole
+stderr=serial,vidconsole
+
+bootdelay=0
+bootcmd=bootefi bootmgr; pause; bootmenu
+
+fastbootcmd=echo "Fastboot Mode";
+ fastboot -l $fastboot_addr_r usb 0
+
+bootmenu_0=Continue Boot=boot
+bootmenu_1=Enter Fastboot Mode=run fastbootcmd
+bootmenu_2=UEFI Maintenance Menu=eficonfig
+bootmenu_3=Reboot=reset
+bootmenu_4=Power Off=poweroff
+
+button_cmd_0_name=Volume Down Key
+button_cmd_0=bootmenu