1ffa8f8b7SJoseph Chen // SPDX-License-Identifier: GPL-2.0 2ffa8f8b7SJoseph Chen /* 3ffa8f8b7SJoseph Chen * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd 4ffa8f8b7SJoseph Chen */ 5ffa8f8b7SJoseph Chen 6ffa8f8b7SJoseph Chen #include <common.h> 7ffa8f8b7SJoseph Chen #include <sysmem.h> 8ffa8f8b7SJoseph Chen #include <lmb.h> 9ffa8f8b7SJoseph Chen #include <malloc.h> 10ffa8f8b7SJoseph Chen #include <asm/io.h> 11ffa8f8b7SJoseph Chen 12ffa8f8b7SJoseph Chen DECLARE_GLOBAL_DATA_PTR; 13ffa8f8b7SJoseph Chen 14ffa8f8b7SJoseph Chen #define SYSMEM_MAGIC 0x4D454D53 /* "SMEM" */ 15*598774ecSJoseph Chen 16*598774ecSJoseph Chen #define LMB_ALLOC_ANYWHERE 0 /* sync with lmb.c */ 17ffa8f8b7SJoseph Chen #define SYSMEM_ALLOC_NO_ALIGN 1 18*598774ecSJoseph Chen #define SYSMEM_ALLOC_ANYWHERE 2 19ffa8f8b7SJoseph Chen 20ffa8f8b7SJoseph Chen #define SYSMEM_I(fmt, args...) printf("Sysmem: "fmt, ##args) 21ffa8f8b7SJoseph Chen #define SYSMEM_W(fmt, args...) printf("Sysmem Warn: "fmt, ##args) 22ffa8f8b7SJoseph Chen #define SYSMEM_E(fmt, args...) printf("Sysmem Error: "fmt, ##args) 23ffa8f8b7SJoseph Chen #define SYSMEM_D(fmt, args...) debug("Sysmem Debug: "fmt, ##args) 24ffa8f8b7SJoseph Chen 256e15146eSJoseph Chen struct memcheck { 26ffa8f8b7SJoseph Chen uint32_t magic; 27ffa8f8b7SJoseph Chen }; 28ffa8f8b7SJoseph Chen 296e15146eSJoseph Chen /* Global for platform, must in data section */ 306e15146eSJoseph Chen struct sysmem plat_sysmem __section(".data") = { 316e15146eSJoseph Chen .has_initf = false, 326e15146eSJoseph Chen .has_initr = false, 336e15146eSJoseph Chen }; 34ffa8f8b7SJoseph Chen 356e15146eSJoseph Chen bool sysmem_has_init(void) 366e15146eSJoseph Chen { 376e15146eSJoseph Chen return gd->flags & GD_FLG_RELOC ? 386e15146eSJoseph Chen plat_sysmem.has_initr : plat_sysmem.has_initf; 39ffa8f8b7SJoseph Chen } 40ffa8f8b7SJoseph Chen 41ffa8f8b7SJoseph Chen void sysmem_dump(void) 42ffa8f8b7SJoseph Chen { 43ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 44ffa8f8b7SJoseph Chen struct lmb *lmb = &sysmem->lmb; 456e15146eSJoseph Chen struct memblock *mem; 466e15146eSJoseph Chen struct memcheck *check; 47ffa8f8b7SJoseph Chen struct list_head *node; 48ffa8f8b7SJoseph Chen ulong memory_size = 0; 49ffa8f8b7SJoseph Chen ulong reserved_size = 0; 50ffa8f8b7SJoseph Chen ulong allocated_size = 0; 516e15146eSJoseph Chen bool overflow = false; 52ffa8f8b7SJoseph Chen ulong i; 53ffa8f8b7SJoseph Chen 54ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 55ffa8f8b7SJoseph Chen return; 56ffa8f8b7SJoseph Chen 57ffa8f8b7SJoseph Chen printf("\nsysmem_dump_all:\n"); 58ffa8f8b7SJoseph Chen 59ffa8f8b7SJoseph Chen /* Memory pool */ 606e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n"); 61ffa8f8b7SJoseph Chen for (i = 0; i < lmb->memory.cnt; i++) { 62ffa8f8b7SJoseph Chen memory_size += lmb->memory.region[i].size; 636e15146eSJoseph Chen printf(" memory.rgn[%ld].addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", i, 646e15146eSJoseph Chen (ulong)lmb->memory.region[i].base, 656e15146eSJoseph Chen (ulong)lmb->memory.region[i].base + 666e15146eSJoseph Chen (ulong)lmb->memory.region[i].size, 67ffa8f8b7SJoseph Chen (ulong)lmb->memory.region[i].size); 68ffa8f8b7SJoseph Chen } 69ffa8f8b7SJoseph Chen printf("\n memory.total = 0x%08lx (%ld MiB. %ld KiB)\n", 70ffa8f8b7SJoseph Chen (ulong)memory_size, 71ffa8f8b7SJoseph Chen SIZE_MB((ulong)memory_size), 72ffa8f8b7SJoseph Chen SIZE_KB((ulong)memory_size)); 73ffa8f8b7SJoseph Chen 74ffa8f8b7SJoseph Chen /* Allocated */ 75ffa8f8b7SJoseph Chen i = 0; 766e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n"); 77ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 786e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 796e15146eSJoseph Chen allocated_size += mem->size; 806e15146eSJoseph Chen if (mem->attr.flags & M_ATTR_OFC) { 816e15146eSJoseph Chen check = (struct memcheck *) 826e15146eSJoseph Chen (mem->base + mem->size - sizeof(*check)); 836e15146eSJoseph Chen overflow = (check->magic != SYSMEM_MAGIC); 846e15146eSJoseph Chen } else if (mem->attr.flags & M_ATTR_HOFC) { 856e15146eSJoseph Chen check = (struct memcheck *) 866e15146eSJoseph Chen (mem->base - sizeof(*check)); 876e15146eSJoseph Chen overflow = (check->magic != SYSMEM_MAGIC); 886e15146eSJoseph Chen } else { 896e15146eSJoseph Chen overflow = false; 906e15146eSJoseph Chen } 916e15146eSJoseph Chen 92ffa8f8b7SJoseph Chen printf(" allocated.rgn[%ld].name = \"%s\" %s\n", 936e15146eSJoseph Chen i, mem->attr.name, overflow ? " <Overflow!>" : ""); 946e15146eSJoseph Chen printf(" .addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", 956e15146eSJoseph Chen (ulong)mem->base, (ulong)(mem->base + mem->size), 966e15146eSJoseph Chen (ulong)mem->size); 97ffa8f8b7SJoseph Chen i++; 98ffa8f8b7SJoseph Chen } 996e15146eSJoseph Chen 1006e15146eSJoseph Chen printf("\n malloc_r: %d MiB, malloc_f: %d KiB\n", 1016e15146eSJoseph Chen SIZE_MB(CONFIG_SYS_MALLOC_LEN), SIZE_KB(CONFIG_SYS_MALLOC_F_LEN)); 102ffa8f8b7SJoseph Chen printf("\n allocated.total = 0x%08lx (%ld MiB. %ld KiB)\n", 103ffa8f8b7SJoseph Chen (ulong)allocated_size, 104ffa8f8b7SJoseph Chen SIZE_MB((ulong)allocated_size), 105ffa8f8b7SJoseph Chen SIZE_KB((ulong)allocated_size)); 106ffa8f8b7SJoseph Chen 107ffa8f8b7SJoseph Chen /* LMB core reserved */ 1086e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n"); 109ffa8f8b7SJoseph Chen reserved_size = 0; 110ffa8f8b7SJoseph Chen for (i = 0; i < lmb->reserved.cnt; i++) { 111ffa8f8b7SJoseph Chen reserved_size += lmb->reserved.region[i].size; 1126e15146eSJoseph Chen printf(" LMB.reserved[%ld].addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", i, 1136e15146eSJoseph Chen (ulong)lmb->reserved.region[i].base, 1146e15146eSJoseph Chen (ulong)lmb->reserved.region[i].base + 1156e15146eSJoseph Chen (ulong)lmb->reserved.region[i].size, 116ffa8f8b7SJoseph Chen (ulong)lmb->reserved.region[i].size); 117ffa8f8b7SJoseph Chen } 118ffa8f8b7SJoseph Chen 119ffa8f8b7SJoseph Chen printf("\n reserved.core.total = 0x%08lx (%ld MiB. %ld KiB)\n", 120ffa8f8b7SJoseph Chen (ulong)reserved_size, 121ffa8f8b7SJoseph Chen SIZE_MB((ulong)reserved_size), 122ffa8f8b7SJoseph Chen SIZE_KB((ulong)reserved_size)); 1236e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n\n"); 124ffa8f8b7SJoseph Chen } 125ffa8f8b7SJoseph Chen 1266e15146eSJoseph Chen static inline int sysmem_is_overlap(phys_addr_t base1, phys_size_t size1, 127ffa8f8b7SJoseph Chen phys_addr_t base2, phys_size_t size2) 128ffa8f8b7SJoseph Chen { 129ffa8f8b7SJoseph Chen return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); 130ffa8f8b7SJoseph Chen } 131ffa8f8b7SJoseph Chen 1326e15146eSJoseph Chen static int sysmem_add(phys_addr_t base, phys_size_t size) 133ffa8f8b7SJoseph Chen { 134ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 135ffa8f8b7SJoseph Chen int ret; 136ffa8f8b7SJoseph Chen 1376e15146eSJoseph Chen if (!size) 1386e15146eSJoseph Chen return -EINVAL; 139ffa8f8b7SJoseph Chen 140ffa8f8b7SJoseph Chen ret = lmb_add(&sysmem->lmb, base, size); 141ffa8f8b7SJoseph Chen if (ret < 0) 1426e15146eSJoseph Chen SYSMEM_E("Failed to add sysmem at 0x%08lx for 0x%08lx size\n", 143ffa8f8b7SJoseph Chen (ulong)base, (ulong)size); 144ffa8f8b7SJoseph Chen 145ffa8f8b7SJoseph Chen return (ret >= 0) ? 0 : ret; 146ffa8f8b7SJoseph Chen } 147ffa8f8b7SJoseph Chen 1486e15146eSJoseph Chen static const char *sysmem_alias2name(const char *name, int *id) 149ffa8f8b7SJoseph Chen { 1506e15146eSJoseph Chen const char *alias; 1516e15146eSJoseph Chen int n, i, j; 1526e15146eSJoseph Chen int match = 0; 153ffa8f8b7SJoseph Chen 1546e15146eSJoseph Chen for (i = 0; i < MEMBLK_ID_MAX; i++) { 1556e15146eSJoseph Chen /* Pirmary name */ 1566e15146eSJoseph Chen if (mem_attr[i].name && !strcasecmp(mem_attr[i].name, name)) { 1576e15146eSJoseph Chen match = 1; 1586e15146eSJoseph Chen goto finish; 159ffa8f8b7SJoseph Chen } 160ffa8f8b7SJoseph Chen 1616e15146eSJoseph Chen /* Alias name */ 1626e15146eSJoseph Chen alias = mem_attr[i].alias[0]; 1636e15146eSJoseph Chen if (!alias) 1646e15146eSJoseph Chen continue; 1656e15146eSJoseph Chen 1666e15146eSJoseph Chen n = ARRAY_SIZE(mem_attr[i].alias); 1676e15146eSJoseph Chen for (j = 0; j < n; j++, alias++) { 1686e15146eSJoseph Chen if (alias && !strcasecmp(alias, name)) { 1696e15146eSJoseph Chen match = 1; 1706e15146eSJoseph Chen goto finish; 1716e15146eSJoseph Chen } 172ffa8f8b7SJoseph Chen } 173ffa8f8b7SJoseph Chen } 174ffa8f8b7SJoseph Chen 1756e15146eSJoseph Chen finish: 1766e15146eSJoseph Chen if (match) { 1776e15146eSJoseph Chen *id = i; 1786e15146eSJoseph Chen return mem_attr[i].name; 179ffa8f8b7SJoseph Chen } 180ffa8f8b7SJoseph Chen 1816e15146eSJoseph Chen return name; 182ffa8f8b7SJoseph Chen } 183ffa8f8b7SJoseph Chen 1846e15146eSJoseph Chen static void *sysmem_alloc_align_base(enum memblk_id id, 1856e15146eSJoseph Chen const char *mem_name, 186ffa8f8b7SJoseph Chen phys_addr_t base, 187ffa8f8b7SJoseph Chen phys_size_t size, 188ffa8f8b7SJoseph Chen ulong align) 189ffa8f8b7SJoseph Chen { 190ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 1916e15146eSJoseph Chen struct memblk_attr attr; 1926e15146eSJoseph Chen struct memblock *mem; 1936e15146eSJoseph Chen struct memcheck *check; 194ffa8f8b7SJoseph Chen struct list_head *node; 1956e15146eSJoseph Chen const char *name; 196ffa8f8b7SJoseph Chen phys_addr_t paddr; 197ffa8f8b7SJoseph Chen phys_addr_t alloc_base; 198ffa8f8b7SJoseph Chen phys_size_t alloc_size; 199305d8903SJoseph Chen phys_addr_t bank_base; 200305d8903SJoseph Chen phys_size_t bank_size; 201305d8903SJoseph Chen bool req_overlap = false; /* Only for kernel reserved-memory */ 202305d8903SJoseph Chen int i; 203ffa8f8b7SJoseph Chen 204ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 205efda1f1dSJoseph Chen goto out; 206ffa8f8b7SJoseph Chen 2076e15146eSJoseph Chen if (id == MEMBLK_ID_BY_NAME || id == MEMBLK_ID_FDT_RESV) { 2086e15146eSJoseph Chen if (!mem_name) { 209ffa8f8b7SJoseph Chen SYSMEM_E("NULL name for alloc sysmem\n"); 210efda1f1dSJoseph Chen goto out; 2116e15146eSJoseph Chen } else if (id == MEMBLK_ID_FDT_RESV) { 212efda1f1dSJoseph Chen 213efda1f1dSJoseph Chen /* 214efda1f1dSJoseph Chen * Allow fdt reserved memory to overlap with the region 215efda1f1dSJoseph Chen * only used in U-Boot, like: stack, fastboot, u-boot... 216efda1f1dSJoseph Chen * these regions are marked as M_ATTR_OVERLAP in flags. 217efda1f1dSJoseph Chen * 218efda1f1dSJoseph Chen * Here we check whether it overlaps with others, if 219efda1f1dSJoseph Chen * so, set req_overlap as true. 220efda1f1dSJoseph Chen */ 221305d8903SJoseph Chen for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 222305d8903SJoseph Chen if (!gd->bd->bi_dram[i].size) 223305d8903SJoseph Chen continue; 224305d8903SJoseph Chen 225305d8903SJoseph Chen bank_base = gd->bd->bi_dram[i].start; 226305d8903SJoseph Chen bank_size = gd->bd->bi_dram[i].size; 227305d8903SJoseph Chen if (sysmem_is_overlap(base, size, 228305d8903SJoseph Chen bank_base, bank_size)) { 2296e15146eSJoseph Chen req_overlap = true; 230305d8903SJoseph Chen break; 231305d8903SJoseph Chen } 232305d8903SJoseph Chen } 233305d8903SJoseph Chen 234efda1f1dSJoseph Chen /* 235efda1f1dSJoseph Chen * If this request region is out size of all available 236efda1f1dSJoseph Chen * region, ignore and return success. 237efda1f1dSJoseph Chen */ 238305d8903SJoseph Chen if (!req_overlap) 2396e15146eSJoseph Chen return (void *)base; 2406e15146eSJoseph Chen } 241efda1f1dSJoseph Chen 242efda1f1dSJoseph Chen /* Find name, id and attr by outer mem_name */ 2436e15146eSJoseph Chen name = sysmem_alias2name(mem_name, (int *)&id); 2446e15146eSJoseph Chen attr = mem_attr[id]; 245a90f2861SJoseph Chen if (!attr.name) 246a90f2861SJoseph Chen attr.name = strdup(name); 2476e15146eSJoseph Chen } else if (id > MEMBLK_ID_UNK && id < MEMBLK_ID_MAX) { 2486e15146eSJoseph Chen attr = mem_attr[id]; 2496e15146eSJoseph Chen name = attr.name; 250f6e15301SJoseph Chen 251f6e15301SJoseph Chen /* 252f6e15301SJoseph Chen * Fixup base and place right after U-Boot stack, adding a lot 253f6e15301SJoseph Chen * of space(4KB) maybe safer. 254f6e15301SJoseph Chen */ 255f6e15301SJoseph Chen if ((id == MEMBLK_ID_AVB_ANDROID) && 256*598774ecSJoseph Chen (base == SYSMEM_ALLOC_ANYWHERE)) { 257f6e15301SJoseph Chen base = gd->start_addr_sp - 258f6e15301SJoseph Chen CONFIG_SYS_STACK_SIZE - size - 0x1000; 259*598774ecSJoseph Chen /* 260*598774ecSJoseph Chen * So far, we use M_ATTR_PEEK for uncompress kernel alloc, and 261*598774ecSJoseph Chen * for ARMv8 enabling AArch32 mode, the ATF is still AArch64 262*598774ecSJoseph Chen * and ocuppies 0~1MB and shmem 1~2M. So let's ignore the region 263*598774ecSJoseph Chen * which overlap with them. 264*598774ecSJoseph Chen */ 265*598774ecSJoseph Chen } else if (attr.flags & M_ATTR_PEEK) { 266*598774ecSJoseph Chen if (base <= gd->bd->bi_dram[0].start) 267*598774ecSJoseph Chen base = gd->bd->bi_dram[0].start; 268*598774ecSJoseph Chen } 2696e15146eSJoseph Chen } else { 2706e15146eSJoseph Chen SYSMEM_E("Unsupport memblk id %d for alloc sysmem\n", id); 271efda1f1dSJoseph Chen goto out; 2726e15146eSJoseph Chen } 2736e15146eSJoseph Chen 2746e15146eSJoseph Chen if (!size) { 2756e15146eSJoseph Chen SYSMEM_E("\"%s\" size is 0 for alloc sysmem\n", name); 276efda1f1dSJoseph Chen goto out; 277ffa8f8b7SJoseph Chen } 278ffa8f8b7SJoseph Chen 279727ebf6dSJoseph Chen if (!IS_ALIGNED(base, 4)) { 2806e15146eSJoseph Chen SYSMEM_E("\"%s\" base=0x%08lx is not 4-byte aligned\n", 2816e15146eSJoseph Chen name, (ulong)base); 282efda1f1dSJoseph Chen goto out; 283727ebf6dSJoseph Chen } 284727ebf6dSJoseph Chen 285727ebf6dSJoseph Chen /* Must be 4-byte aligned */ 286727ebf6dSJoseph Chen size = ALIGN(size, 4); 287727ebf6dSJoseph Chen 2886e15146eSJoseph Chen SYSMEM_D("Enter alloc: \"%s\" 0x%08lx - 0x%08lx\n", 2896e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size)); 2906e15146eSJoseph Chen 291ffa8f8b7SJoseph Chen /* Already allocated ? */ 292ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 2936e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 2946e15146eSJoseph Chen SYSMEM_D("Has allcated: %s, 0x%08lx - 0x%08lx\n", 2956e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 2966e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 2976e15146eSJoseph Chen if (!strcmp(mem->attr.name, name)) { 298efda1f1dSJoseph Chen /* Allow double alloc for same but smaller region */ 2992cb995bcSJoseph Chen if (mem->base <= base && mem->size >= size) 3002cb995bcSJoseph Chen return (void *)base; 3012cb995bcSJoseph Chen 302ffa8f8b7SJoseph Chen SYSMEM_E("Failed to double alloc for existence \"%s\"\n", name); 303efda1f1dSJoseph Chen goto out; 3046e15146eSJoseph Chen } else if (sysmem_is_overlap(mem->base, mem->size, base, size)) { 305efda1f1dSJoseph Chen /* 306efda1f1dSJoseph Chen * If this new alloc region expects overlap and the old 307efda1f1dSJoseph Chen * region is also allowed to be overlap, just do reserve. 308efda1f1dSJoseph Chen */ 3096e15146eSJoseph Chen if (req_overlap && mem->attr.flags & M_ATTR_OVERLAP) { 3106e15146eSJoseph Chen if (lmb_reserve(&sysmem->lmb, base, size)) 3116e15146eSJoseph Chen SYSMEM_E("Failed to overlap alloc \"%s\" " 3126e15146eSJoseph Chen "at 0x%08lx - 0x%08lx\n", 3136e15146eSJoseph Chen name, (ulong)base, 3146e15146eSJoseph Chen (ulong)(base + size)); 3156e15146eSJoseph Chen return (void *)base; 3166e15146eSJoseph Chen } 3176e15146eSJoseph Chen 3186e15146eSJoseph Chen SYSMEM_E("\"%s\" (0x%08lx - 0x%08lx) alloc is " 3196e15146eSJoseph Chen "overlap with existence \"%s\" (0x%08lx - " 3206e15146eSJoseph Chen "0x%08lx)\n", 3216e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size), 3226e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 3236e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 324efda1f1dSJoseph Chen goto out; 325ffa8f8b7SJoseph Chen } 326ffa8f8b7SJoseph Chen } 327ffa8f8b7SJoseph Chen 3286e15146eSJoseph Chen /* Add overflow check magic ? */ 3296e15146eSJoseph Chen if (attr.flags & M_ATTR_OFC) 330ffa8f8b7SJoseph Chen alloc_size = size + sizeof(*check); 3316e15146eSJoseph Chen else 3326e15146eSJoseph Chen alloc_size = size; 3336e15146eSJoseph Chen 3346e15146eSJoseph Chen /* Alloc anywhere ? */ 335ffa8f8b7SJoseph Chen if (base == SYSMEM_ALLOC_ANYWHERE) 336*598774ecSJoseph Chen alloc_base = LMB_ALLOC_ANYWHERE; 337ffa8f8b7SJoseph Chen else 338ffa8f8b7SJoseph Chen alloc_base = base + alloc_size; /* LMB is align down alloc mechanism */ 339ffa8f8b7SJoseph Chen 340ffa8f8b7SJoseph Chen paddr = lmb_alloc_base(&sysmem->lmb, alloc_size, align, alloc_base); 341ffa8f8b7SJoseph Chen if (paddr) { 342ffa8f8b7SJoseph Chen if ((paddr == base) || (base == SYSMEM_ALLOC_ANYWHERE)) { 3436e15146eSJoseph Chen mem = malloc(sizeof(*mem)); 3446e15146eSJoseph Chen if (!mem) { 345ffa8f8b7SJoseph Chen SYSMEM_E("No memory for \"%s\" alloc sysmem\n", name); 346efda1f1dSJoseph Chen goto out; 347ffa8f8b7SJoseph Chen } 348ffa8f8b7SJoseph Chen 3496e15146eSJoseph Chen mem->base = paddr; 3506e15146eSJoseph Chen mem->size = alloc_size; 3516e15146eSJoseph Chen mem->attr = attr; 352ffa8f8b7SJoseph Chen sysmem->allocated_cnt++; 3536e15146eSJoseph Chen list_add_tail(&mem->node, &sysmem->allocated_head); 354ffa8f8b7SJoseph Chen 355efda1f1dSJoseph Chen /* Add overflow check magic */ 3566e15146eSJoseph Chen if (mem->attr.flags & M_ATTR_OFC) { 3576e15146eSJoseph Chen check = (struct memcheck *)(paddr + size); 358ffa8f8b7SJoseph Chen check->magic = SYSMEM_MAGIC; 3596e15146eSJoseph Chen } else if (mem->attr.flags & M_ATTR_HOFC) { 3606e15146eSJoseph Chen check = (struct memcheck *)(paddr - sizeof(*check)); 3616e15146eSJoseph Chen check->magic = SYSMEM_MAGIC; 3626e15146eSJoseph Chen } 363ffa8f8b7SJoseph Chen } else { 3646e15146eSJoseph Chen SYSMEM_E("Failed to alloc \"%s\" expect at 0x%08lx - 0x%08lx " 3656e15146eSJoseph Chen "but at 0x%08lx - x%08lx\n", 3666e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size), 3676e15146eSJoseph Chen (ulong)paddr, (ulong)(paddr + size)); 368efda1f1dSJoseph Chen /* Free what we don't want allocated region */ 3693bee194fSJoseph Chen if (lmb_free(&sysmem->lmb, paddr, alloc_size) < 0) 3706e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\"\n", name); 3716e15146eSJoseph Chen 372efda1f1dSJoseph Chen goto out; 373ffa8f8b7SJoseph Chen } 374ffa8f8b7SJoseph Chen } else { 3756e15146eSJoseph Chen SYSMEM_E("Failed to alloc \"%s\" at 0x%08lx - 0x%08lx\n", 3766e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size)); 377661cbb0bSJoseph Chen goto out; 378ffa8f8b7SJoseph Chen } 379ffa8f8b7SJoseph Chen 3806e15146eSJoseph Chen SYSMEM_D("Exit alloc: \"%s\", paddr=0x%08lx, size=0x%08lx, align=0x%x, anywhere=%d\n", 381ffa8f8b7SJoseph Chen name, (ulong)paddr, (ulong)size, (u32)align, !base); 382ffa8f8b7SJoseph Chen 383ffa8f8b7SJoseph Chen return (void *)paddr; 384efda1f1dSJoseph Chen 385efda1f1dSJoseph Chen out: 386*598774ecSJoseph Chen /* 387*598774ecSJoseph Chen * Why: base + sizeof(ulong) ? 388*598774ecSJoseph Chen * It's a not standard way to handle the case: the input base is 0. 389*598774ecSJoseph Chen */ 390*598774ecSJoseph Chen if (base == 0) 391*598774ecSJoseph Chen base = base + sizeof(ulong); 392*598774ecSJoseph Chen 393efda1f1dSJoseph Chen return (attr.flags & M_ATTR_PEEK) ? (void *)base : NULL; 394ffa8f8b7SJoseph Chen } 395ffa8f8b7SJoseph Chen 396dcb404a6SJoseph Chen void *sysmem_alloc(enum memblk_id id, phys_size_t size) 397dcb404a6SJoseph Chen { 398dcb404a6SJoseph Chen void *paddr; 399dcb404a6SJoseph Chen 400dcb404a6SJoseph Chen paddr = sysmem_alloc_align_base(id, 401dcb404a6SJoseph Chen NULL, 402dcb404a6SJoseph Chen SYSMEM_ALLOC_ANYWHERE, 403dcb404a6SJoseph Chen size, 404dcb404a6SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 405dcb404a6SJoseph Chen if (!paddr) 406dcb404a6SJoseph Chen sysmem_dump(); 407dcb404a6SJoseph Chen 408dcb404a6SJoseph Chen return paddr; 409dcb404a6SJoseph Chen } 410dcb404a6SJoseph Chen 4116e15146eSJoseph Chen void *sysmem_alloc_base(enum memblk_id id, phys_addr_t base, phys_size_t size) 412ffa8f8b7SJoseph Chen { 4136e15146eSJoseph Chen void *paddr; 414ffa8f8b7SJoseph Chen 4156e15146eSJoseph Chen paddr = sysmem_alloc_align_base(id, 4166e15146eSJoseph Chen NULL, 417ffa8f8b7SJoseph Chen base, 418ffa8f8b7SJoseph Chen size, 419ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 4206e15146eSJoseph Chen if (!paddr) 4216e15146eSJoseph Chen sysmem_dump(); 4226e15146eSJoseph Chen 4236e15146eSJoseph Chen return paddr; 424ffa8f8b7SJoseph Chen } 425ffa8f8b7SJoseph Chen 4266e15146eSJoseph Chen void *sysmem_alloc_base_by_name(const char *name, 4276e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 428ffa8f8b7SJoseph Chen { 4296e15146eSJoseph Chen void *paddr; 4306e15146eSJoseph Chen 4316e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_BY_NAME, 4326e15146eSJoseph Chen name, 4336e15146eSJoseph Chen base, 434ffa8f8b7SJoseph Chen size, 435ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 4366e15146eSJoseph Chen if (!paddr) 4376e15146eSJoseph Chen sysmem_dump(); 4386e15146eSJoseph Chen 4396e15146eSJoseph Chen return paddr; 4406e15146eSJoseph Chen } 4416e15146eSJoseph Chen 4426e15146eSJoseph Chen void *sysmem_fdt_reserve_alloc_base(const char *name, 4436e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 4446e15146eSJoseph Chen { 4456e15146eSJoseph Chen void *paddr; 4466e15146eSJoseph Chen 4476e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_FDT_RESV, 4486e15146eSJoseph Chen name, 4496e15146eSJoseph Chen base, 4506e15146eSJoseph Chen size, 4516e15146eSJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 4526e15146eSJoseph Chen if (!paddr) 4536e15146eSJoseph Chen sysmem_dump(); 4546e15146eSJoseph Chen 4556e15146eSJoseph Chen return paddr; 456ffa8f8b7SJoseph Chen } 457ffa8f8b7SJoseph Chen 4583bee194fSJoseph Chen bool sysmem_can_alloc(phys_size_t base, phys_size_t size) 4593bee194fSJoseph Chen { 4603bee194fSJoseph Chen struct sysmem *sysmem = &plat_sysmem; 4613bee194fSJoseph Chen phys_addr_t alloc_base; 4623bee194fSJoseph Chen phys_addr_t paddr; 4633bee194fSJoseph Chen int ret; 4643bee194fSJoseph Chen 4653bee194fSJoseph Chen if (!sysmem_has_init()) 4663bee194fSJoseph Chen return false; 4673bee194fSJoseph Chen 4683bee194fSJoseph Chen /* LMB is align down alloc mechanism */ 4693bee194fSJoseph Chen alloc_base = base + size; 4703bee194fSJoseph Chen paddr = __lmb_alloc_base(&sysmem->lmb, 4713bee194fSJoseph Chen size, 4723bee194fSJoseph Chen SYSMEM_ALLOC_NO_ALIGN, 4733bee194fSJoseph Chen alloc_base); 4743bee194fSJoseph Chen if (paddr) { 4753bee194fSJoseph Chen /* If free failed, return false */ 4763bee194fSJoseph Chen ret = lmb_free(&sysmem->lmb, base, size); 4773bee194fSJoseph Chen if (ret < 0) { 4783bee194fSJoseph Chen SYSMEM_E("Can't free at 0x%08lx - 0x%08lx, ret=%d\n", 4793bee194fSJoseph Chen (ulong)base, (ulong)(base + size), ret); 4803bee194fSJoseph Chen return false; 4813bee194fSJoseph Chen } 4823bee194fSJoseph Chen } else { 4833bee194fSJoseph Chen SYSMEM_D("Can't alloc at 0x%08lx - 0x%08lx\n", 4843bee194fSJoseph Chen (ulong)base, (ulong)(base + size)); 4853bee194fSJoseph Chen } 4863bee194fSJoseph Chen 4873bee194fSJoseph Chen return (paddr == base) ? true : false; 4883bee194fSJoseph Chen } 4893bee194fSJoseph Chen 490ffa8f8b7SJoseph Chen int sysmem_free(phys_addr_t base) 491ffa8f8b7SJoseph Chen { 492ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 4936e15146eSJoseph Chen struct memblock *mem; 494ffa8f8b7SJoseph Chen struct list_head *node; 4956e15146eSJoseph Chen int ret, found = 0; 496ffa8f8b7SJoseph Chen 497ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 498ffa8f8b7SJoseph Chen return -ENOSYS; 499ffa8f8b7SJoseph Chen 500ffa8f8b7SJoseph Chen /* Find existence */ 501ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 5026e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 5036e15146eSJoseph Chen if (mem->base == base) { 504ffa8f8b7SJoseph Chen found = 1; 505ffa8f8b7SJoseph Chen break; 506ffa8f8b7SJoseph Chen } 507ffa8f8b7SJoseph Chen } 508ffa8f8b7SJoseph Chen 509ffa8f8b7SJoseph Chen if (!found) { 5106e15146eSJoseph Chen SYSMEM_E("Failed to free no allocated sysmem at 0x%08lx\n", 5116e15146eSJoseph Chen (ulong)base); 512ffa8f8b7SJoseph Chen return -EINVAL; 513ffa8f8b7SJoseph Chen } 514ffa8f8b7SJoseph Chen 5156e15146eSJoseph Chen ret = lmb_free(&sysmem->lmb, mem->base, mem->size); 516ffa8f8b7SJoseph Chen if (ret >= 0) { 5176e15146eSJoseph Chen SYSMEM_D("Free: \"%s\" 0x%08lx - 0x%08lx\n", 5186e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 5196e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 520ffa8f8b7SJoseph Chen sysmem->allocated_cnt--; 5216e15146eSJoseph Chen list_del(&mem->node); 5226e15146eSJoseph Chen free(mem); 523ffa8f8b7SJoseph Chen } else { 5246e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\" at 0x%08lx\n", 5256e15146eSJoseph Chen mem->attr.name, (ulong)base); 526ffa8f8b7SJoseph Chen } 527ffa8f8b7SJoseph Chen 528ffa8f8b7SJoseph Chen return (ret >= 0) ? 0 : ret; 529ffa8f8b7SJoseph Chen } 530ffa8f8b7SJoseph Chen 5316e15146eSJoseph Chen int sysmem_initr(void) 5326e15146eSJoseph Chen { 5336e15146eSJoseph Chen return sysmem_init(); 5346e15146eSJoseph Chen } 5356e15146eSJoseph Chen 536ffa8f8b7SJoseph Chen int sysmem_init(void) 537ffa8f8b7SJoseph Chen { 538ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 539ffa8f8b7SJoseph Chen phys_addr_t mem_start; 540ffa8f8b7SJoseph Chen phys_size_t mem_size; 541ffa8f8b7SJoseph Chen int ret; 542ffa8f8b7SJoseph Chen 543ffa8f8b7SJoseph Chen lmb_init(&sysmem->lmb); 544ffa8f8b7SJoseph Chen INIT_LIST_HEAD(&sysmem->allocated_head); 545ffa8f8b7SJoseph Chen sysmem->allocated_cnt = 0; 5466e15146eSJoseph Chen if (gd->flags & GD_FLG_RELOC) { 5476e15146eSJoseph Chen sysmem->has_initr = true; 5486e15146eSJoseph Chen } else { 5496e15146eSJoseph Chen SYSMEM_I("init\n"); 5506e15146eSJoseph Chen sysmem->has_initf = true; 5516e15146eSJoseph Chen } 552ffa8f8b7SJoseph Chen 553ffa8f8b7SJoseph Chen /* Add all available system memory */ 554ffa8f8b7SJoseph Chen #ifdef CONFIG_NR_DRAM_BANKS 555ffa8f8b7SJoseph Chen int i; 556ffa8f8b7SJoseph Chen 557ffa8f8b7SJoseph Chen for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 5586e15146eSJoseph Chen if (!gd->bd->bi_dram[i].size) 5596e15146eSJoseph Chen continue; 5606e15146eSJoseph Chen 561ffa8f8b7SJoseph Chen ret = sysmem_add(gd->bd->bi_dram[i].start, 562ffa8f8b7SJoseph Chen gd->bd->bi_dram[i].size); 563ffa8f8b7SJoseph Chen if (ret) { 564ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bi_dram[%d]\n", i); 5656e15146eSJoseph Chen goto fail; 566ffa8f8b7SJoseph Chen } 567ffa8f8b7SJoseph Chen } 568ffa8f8b7SJoseph Chen #else 569ffa8f8b7SJoseph Chen mem_start = env_get_bootm_low(); 570ffa8f8b7SJoseph Chen mem_size = env_get_bootm_size(); 571ffa8f8b7SJoseph Chen ret = sysmem_add(mem_start, mem_size); 572ffa8f8b7SJoseph Chen if (ret) { 573ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bootm_low/size\n"); 5746e15146eSJoseph Chen goto fail; 575ffa8f8b7SJoseph Chen } 576ffa8f8b7SJoseph Chen #endif 577ffa8f8b7SJoseph Chen /* Reserved for board */ 578ffa8f8b7SJoseph Chen ret = board_sysmem_reserve(sysmem); 579ffa8f8b7SJoseph Chen if (ret) { 580ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for board\n"); 5816e15146eSJoseph Chen goto fail; 582ffa8f8b7SJoseph Chen } 583ffa8f8b7SJoseph Chen 5846e15146eSJoseph Chen /* Reserved for U-boot framework: 'reserve_xxx()' */ 5856e15146eSJoseph Chen mem_start = gd->start_addr_sp; 586ffa8f8b7SJoseph Chen mem_size = gd->ram_top - mem_start; 5876e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_UBOOT, mem_start, mem_size)) { 588ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for U-Boot framework\n"); 5896e15146eSJoseph Chen ret = -ENOMEM; 5906e15146eSJoseph Chen goto fail; 591ffa8f8b7SJoseph Chen } 592ffa8f8b7SJoseph Chen 5936e15146eSJoseph Chen /* Reserved for U-Boot stack */ 5946e15146eSJoseph Chen mem_start = gd->start_addr_sp - CONFIG_SYS_STACK_SIZE; 5956e15146eSJoseph Chen mem_size = CONFIG_SYS_STACK_SIZE; 5966e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_STACK, mem_start, mem_size)) { 5976e15146eSJoseph Chen SYSMEM_E("Failed to reserve sysmem for stack\n"); 5986e15146eSJoseph Chen ret = -ENOMEM; 5996e15146eSJoseph Chen goto fail; 6006e15146eSJoseph Chen } 601ffa8f8b7SJoseph Chen 602ffa8f8b7SJoseph Chen return 0; 6036e15146eSJoseph Chen 6046e15146eSJoseph Chen fail: 6056e15146eSJoseph Chen if (ret && !(gd->flags & GD_FLG_RELOC)) { 6066e15146eSJoseph Chen sysmem_dump(); 6076e15146eSJoseph Chen SYSMEM_W("Maybe malloc size %d MiB is too large?\n\n", 6086e15146eSJoseph Chen SIZE_MB(CONFIG_SYS_MALLOC_LEN)); 6096e15146eSJoseph Chen } 6106e15146eSJoseph Chen 6116e15146eSJoseph Chen return ret; 612ffa8f8b7SJoseph Chen } 613ffa8f8b7SJoseph Chen 614ffa8f8b7SJoseph Chen __weak int board_sysmem_reserve(struct sysmem *sysmem) 615ffa8f8b7SJoseph Chen { 616ffa8f8b7SJoseph Chen /* please define platform specific board_sysmem_reserve() */ 617ffa8f8b7SJoseph Chen return 0; 618ffa8f8b7SJoseph Chen } 619ffa8f8b7SJoseph Chen 6206e15146eSJoseph Chen static int do_dump_sysmem(cmd_tbl_t *cmdtp, int flag, 6216e15146eSJoseph Chen int argc, char *const argv[]) 622ffa8f8b7SJoseph Chen { 6236e15146eSJoseph Chen sysmem_dump(); 624ffa8f8b7SJoseph Chen return 0; 625ffa8f8b7SJoseph Chen } 6266e15146eSJoseph Chen 6276e15146eSJoseph Chen U_BOOT_CMD( 6286e15146eSJoseph Chen dump_sysmem, 1, 1, do_dump_sysmem, 6296e15146eSJoseph Chen "Dump sysmem layout", 6306e15146eSJoseph Chen "" 6316e15146eSJoseph Chen ); 632