diff options
| author | Kaustabh Chakraborty <[email protected]> | 2025-10-24 22:58:27 +0530 |
|---|---|---|
| committer | Minkyu Kang <[email protected]> | 2025-12-02 13:38:27 +0900 |
| commit | ed9ba442ee1f9aea1ab92b10e56c8ac710a770cf (patch) | |
| tree | df1ef0632aa37ded3983d00ef949a111f8dcc61c /board | |
| parent | ff3b4e9936a720870decd6ddb0e77c7b5d464d5d (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/Kconfig | 18 | ||||
| -rw-r--r-- | board/samsung/exynos-mobile/MAINTAINERS | 6 | ||||
| -rw-r--r-- | board/samsung/exynos-mobile/Makefile | 5 | ||||
| -rw-r--r-- | board/samsung/exynos-mobile/exynos-mobile.c | 287 | ||||
| -rw-r--r-- | board/samsung/exynos-mobile/exynos-mobile.env | 18 |
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 |
