// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd */ #include #include #include #include #include #include DECLARE_GLOBAL_DATA_PTR; #define SZ_4GB 0x100000000ULL #if !defined(CONFIG_SPL_BUILD) && !defined(CONFIG_TPL_BUILD) #define SDRAM_OFFSET(offset) (CONFIG_SYS_SDRAM_BASE + (offset)) #define PARAM_DRAM_INFO_OFFSET (SZ_32M) #define PARAM_OPTEE_INFO_OFFSET (SZ_32M + SZ_2M) struct tos_param_t { u32 version; u32 checksum; struct { char name[8]; s64 phy_addr; u32 size; u32 flags; } tee_mem; struct { char name[8]; s64 phy_addr; u32 size; u32 flags; } drm_mem; s64 reserve[8]; }; static uint16_t trust_checksum(const uint8_t *buf, uint16_t len) { uint16_t i, checksum = 0; for (i = 0; i < len; i++) { if (i % 2) checksum += buf[i] << 8; else checksum += buf[i]; } checksum = ~checksum; return checksum; } struct memblock param_parse_atf_mem(void) { struct memblock mem; mem.base = 0; mem.size = 0; #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS struct tag *t = NULL; /* * Get memory region of ATF * * 1. New way: atags info; * 2. Leagcy way: 2MB size and start from ddr 0x0 offset; */ t = atags_get_tag(ATAG_ATF_MEM); if (t && t->u.atf_mem.size) { mem.base = t->u.atf_mem.phy_addr; mem.size = t->u.atf_mem.size; /* Sanity */ if (mem.base + mem.size > SDRAM_OFFSET(SZ_1M)) { printf("%s: ATF reserved region is not within 0-1MB " "offset(0x%08llx-0x%08llx)!\n", __func__, (u64)mem.base, (u64)mem.base + mem.size); return mem; } } #endif /* Legacy */ if (!mem.size) { if (IS_ENABLED(CONFIG_ARM64) || IS_ENABLED(CONFIG_ARM64_BOOT_AARCH32)) { mem.base = SDRAM_OFFSET(0); mem.size = SZ_1M; } } debug("ATF: 0x%llx - 0x%llx\n", (u64)mem.base, (u64)mem.base + mem.size); return mem; } struct memblock param_parse_optee_mem(void) { struct tos_param_t *tos_parameter; struct memblock mem; u32 checksum; mem.base = 0; mem.size = 0; #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS struct tag *t = NULL; /* * Get memory region of OP-TEE * * 1. New way: atags info; * 2. Leagcy way: info in ddr 34M offset; */ t = atags_get_tag(ATAG_TOS_MEM); if (t && (t->u.tos_mem.tee_mem.flags == 1)) { mem.base = t->u.tos_mem.tee_mem.phy_addr; mem.size = t->u.tos_mem.tee_mem.size; } #endif /* Legacy */ if (!mem.size) { tos_parameter = (struct tos_param_t *)(SDRAM_OFFSET(PARAM_OPTEE_INFO_OFFSET)); checksum = trust_checksum((uint8_t *)(unsigned long)tos_parameter + 8, sizeof(struct tos_param_t) - 8); if ((checksum == tos_parameter->checksum) && (tos_parameter->tee_mem.flags == 1)) { mem.base = tos_parameter->tee_mem.phy_addr; mem.size = tos_parameter->tee_mem.size; } } if (mem.size) gd->flags |= GD_FLG_BL32_ENABLED; debug("TOS: 0x%llx - 0x%llx\n", (u64)mem.base, (u64)mem.base + mem.size); return mem; } struct memblock param_parse_common_resv_mem(void) { struct memblock mem; #if defined(CONFIG_ARM64) mem.base = SDRAM_OFFSET(SZ_1M); mem.size = SZ_1M; /* * The ARMv8 platform enabling AArch32 mode should reserve memory the same * as AArch64 mode(because there is no difference about ATF), only some * platform has special request, they are: RK3308. */ #elif defined(CONFIG_ARM64_BOOT_AARCH32) && !defined(CONFIG_ROCKCHIP_RK3308) mem.base = SDRAM_OFFSET(SZ_1M); mem.size = SZ_1M; #else mem.size = 0; #endif return mem; } int param_parse_bootdev(char **devtype, char **devnum) { #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS struct tag *t; t = atags_get_tag(ATAG_BOOTDEV); if (t) { switch (t->u.bootdev.devtype) { #ifdef CONFIG_DM_MMC case BOOT_TYPE_EMMC: *devtype = "mmc"; *devnum = "0"; break; case BOOT_TYPE_SD0: case BOOT_TYPE_SD1: *devtype = "mmc"; *devnum = "1"; /* * If preloader does not pass sdupdate value, we treat it * as a unknown card and call the rkimgtest cmd to find * out what it is. * * If preloader pass sdupdate value as an update card, * we just set "sdfwupdate" to bootargs instead of * calling rkimgtest cmd which consumes time. */ if (t->u.bootdev.sdupdate == SD_UNKNOWN_CARD) { run_command("mmc dev 1", 0); run_command("rkimgtest mmc 1", 0); } else if (t->u.bootdev.sdupdate == SD_UPDATE_CARD) { env_update("bootargs", "sdfwupdate"); } break; #endif #if defined(CONFIG_RKNAND) || defined(CONFIG_RKNANDC_NAND) case BOOT_TYPE_NAND: *devtype = "rknand"; *devnum = "0"; break; #endif #ifdef CONFIG_RKSFC_NAND case BOOT_TYPE_SPI_NAND: *devtype = "spinand"; *devnum = "0"; break; #endif #ifdef CONFIG_RKSFC_NOR case BOOT_TYPE_SPI_NOR: *devtype = "spinor"; *devnum = "1"; break; #endif #ifdef CONFIG_DM_RAMDISK case BOOT_TYPE_RAM: *devtype = "ramdisk"; *devnum = "0"; break; #endif default: printf("Unknown bootdev type: 0x%x\n", t->u.bootdev.devtype); return -EINVAL; } return 0; } #endif return -ENOSYS; } #endif static phys_size_t ddr_mem_get_usable_size(u64 base, u64 size) { return (base + size >= CONFIG_SYS_SDRAM_BASE + SDRAM_MAX_SIZE) ? (CONFIG_SYS_SDRAM_BASE + SDRAM_MAX_SIZE - base) : size; } struct memblock *param_parse_ddr_mem(int *out_count) { struct udevice *dev; struct memblock *mem; struct ram_info ram; int i, ret, count; /* * Get memory region of DDR * * 1. New: atags info; * 2. Leagcy: os register; */ #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS struct tag *t; u64 base, size; int n; t = atags_get_tag(ATAG_DDR_MEM); if (t && t->u.ddr_mem.count) { count = t->u.ddr_mem.count; mem = calloc(count + MEM_RESV_COUNT, sizeof(*mem)); if (!mem) { printf("Calloc ddr memory failed\n"); return 0; } for (i = 0, n = 0; i < count; i++, n++) { base = t->u.ddr_mem.bank[i]; size = t->u.ddr_mem.bank[i + count]; /* 0~4GB */ if (base < SZ_4GB) { mem[n].base = base; mem[n].size = ddr_mem_get_usable_size(base, size); if (base + size > SZ_4GB) { n++; mem[n].base_u64 = SZ_4GB; mem[n].size_u64 = base + size - SZ_4GB; } } else { /* 4GB+ */ mem[n].base_u64 = base; mem[n].size_u64 = size; } assert(n < count + MEM_RESV_COUNT); } *out_count = n; return mem; } #endif /* Leagcy */ ret = uclass_get_device(UCLASS_RAM, 0, &dev); if (ret) { debug("DRAM init failed: %d\n", ret); return NULL; } ret = ram_get_info(dev, &ram); if (ret) { debug("Cannot get DRAM size: %d\n", ret); return NULL; } debug("SDRAM base=%lx, size=%lx\n", (unsigned long)ram.base, (unsigned long)ram.size); count = 1; mem = calloc(1, sizeof(*mem)); if (!mem) { printf("Calloc ddr memory failed\n"); return 0; } for (i = 0; i < count; i++) { mem[i].base = CONFIG_SYS_SDRAM_BASE; mem[i].size = ddr_mem_get_usable_size(mem[i].base, ram.size); } *out_count = count; return mem; }