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" */ 15ffa8f8b7SJoseph Chen #define SYSMEM_ALLOC_ANYWHERE 0 16ffa8f8b7SJoseph Chen #define SYSMEM_ALLOC_NO_ALIGN 1 17ffa8f8b7SJoseph Chen 18ffa8f8b7SJoseph Chen #define SYSMEM_I(fmt, args...) printf("Sysmem: "fmt, ##args) 19ffa8f8b7SJoseph Chen #define SYSMEM_W(fmt, args...) printf("Sysmem Warn: "fmt, ##args) 20ffa8f8b7SJoseph Chen #define SYSMEM_E(fmt, args...) printf("Sysmem Error: "fmt, ##args) 21ffa8f8b7SJoseph Chen #define SYSMEM_D(fmt, args...) debug("Sysmem Debug: "fmt, ##args) 22ffa8f8b7SJoseph Chen 236e15146eSJoseph Chen struct memcheck { 24ffa8f8b7SJoseph Chen uint32_t magic; 25ffa8f8b7SJoseph Chen }; 26ffa8f8b7SJoseph Chen 276e15146eSJoseph Chen /* Global for platform, must in data section */ 286e15146eSJoseph Chen struct sysmem plat_sysmem __section(".data") = { 296e15146eSJoseph Chen .has_initf = false, 306e15146eSJoseph Chen .has_initr = false, 316e15146eSJoseph Chen }; 32ffa8f8b7SJoseph Chen 336e15146eSJoseph Chen bool sysmem_has_init(void) 346e15146eSJoseph Chen { 356e15146eSJoseph Chen return gd->flags & GD_FLG_RELOC ? 366e15146eSJoseph Chen plat_sysmem.has_initr : plat_sysmem.has_initf; 37ffa8f8b7SJoseph Chen } 38ffa8f8b7SJoseph Chen 39ffa8f8b7SJoseph Chen void sysmem_dump(void) 40ffa8f8b7SJoseph Chen { 41ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 42ffa8f8b7SJoseph Chen struct lmb *lmb = &sysmem->lmb; 436e15146eSJoseph Chen struct memblock *mem; 446e15146eSJoseph Chen struct memcheck *check; 45ffa8f8b7SJoseph Chen struct list_head *node; 46ffa8f8b7SJoseph Chen ulong memory_size = 0; 47ffa8f8b7SJoseph Chen ulong reserved_size = 0; 48ffa8f8b7SJoseph Chen ulong allocated_size = 0; 496e15146eSJoseph Chen bool overflow = false; 50ffa8f8b7SJoseph Chen ulong i; 51ffa8f8b7SJoseph Chen 52ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 53ffa8f8b7SJoseph Chen return; 54ffa8f8b7SJoseph Chen 55ffa8f8b7SJoseph Chen printf("\nsysmem_dump_all:\n"); 56ffa8f8b7SJoseph Chen 57ffa8f8b7SJoseph Chen /* Memory pool */ 586e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n"); 59ffa8f8b7SJoseph Chen for (i = 0; i < lmb->memory.cnt; i++) { 60ffa8f8b7SJoseph Chen memory_size += lmb->memory.region[i].size; 616e15146eSJoseph Chen printf(" memory.rgn[%ld].addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", i, 626e15146eSJoseph Chen (ulong)lmb->memory.region[i].base, 636e15146eSJoseph Chen (ulong)lmb->memory.region[i].base + 646e15146eSJoseph Chen (ulong)lmb->memory.region[i].size, 65ffa8f8b7SJoseph Chen (ulong)lmb->memory.region[i].size); 66ffa8f8b7SJoseph Chen } 67ffa8f8b7SJoseph Chen printf("\n memory.total = 0x%08lx (%ld MiB. %ld KiB)\n", 68ffa8f8b7SJoseph Chen (ulong)memory_size, 69ffa8f8b7SJoseph Chen SIZE_MB((ulong)memory_size), 70ffa8f8b7SJoseph Chen SIZE_KB((ulong)memory_size)); 71ffa8f8b7SJoseph Chen 72ffa8f8b7SJoseph Chen /* Allocated */ 73ffa8f8b7SJoseph Chen i = 0; 746e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n"); 75ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 766e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 776e15146eSJoseph Chen allocated_size += mem->size; 786e15146eSJoseph Chen if (mem->attr.flags & M_ATTR_OFC) { 796e15146eSJoseph Chen check = (struct memcheck *) 806e15146eSJoseph Chen (mem->base + mem->size - sizeof(*check)); 816e15146eSJoseph Chen overflow = (check->magic != SYSMEM_MAGIC); 826e15146eSJoseph Chen } else if (mem->attr.flags & M_ATTR_HOFC) { 836e15146eSJoseph Chen check = (struct memcheck *) 846e15146eSJoseph Chen (mem->base - sizeof(*check)); 856e15146eSJoseph Chen overflow = (check->magic != SYSMEM_MAGIC); 866e15146eSJoseph Chen } else { 876e15146eSJoseph Chen overflow = false; 886e15146eSJoseph Chen } 896e15146eSJoseph Chen 90ffa8f8b7SJoseph Chen printf(" allocated.rgn[%ld].name = \"%s\" %s\n", 916e15146eSJoseph Chen i, mem->attr.name, overflow ? " <Overflow!>" : ""); 926e15146eSJoseph Chen printf(" .addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", 936e15146eSJoseph Chen (ulong)mem->base, (ulong)(mem->base + mem->size), 946e15146eSJoseph Chen (ulong)mem->size); 95ffa8f8b7SJoseph Chen i++; 96ffa8f8b7SJoseph Chen } 976e15146eSJoseph Chen 986e15146eSJoseph Chen printf("\n malloc_r: %d MiB, malloc_f: %d KiB\n", 996e15146eSJoseph Chen SIZE_MB(CONFIG_SYS_MALLOC_LEN), SIZE_KB(CONFIG_SYS_MALLOC_F_LEN)); 100ffa8f8b7SJoseph Chen printf("\n allocated.total = 0x%08lx (%ld MiB. %ld KiB)\n", 101ffa8f8b7SJoseph Chen (ulong)allocated_size, 102ffa8f8b7SJoseph Chen SIZE_MB((ulong)allocated_size), 103ffa8f8b7SJoseph Chen SIZE_KB((ulong)allocated_size)); 104ffa8f8b7SJoseph Chen 105ffa8f8b7SJoseph Chen /* LMB core reserved */ 1066e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n"); 107ffa8f8b7SJoseph Chen reserved_size = 0; 108ffa8f8b7SJoseph Chen for (i = 0; i < lmb->reserved.cnt; i++) { 109ffa8f8b7SJoseph Chen reserved_size += lmb->reserved.region[i].size; 1106e15146eSJoseph Chen printf(" LMB.reserved[%ld].addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", i, 1116e15146eSJoseph Chen (ulong)lmb->reserved.region[i].base, 1126e15146eSJoseph Chen (ulong)lmb->reserved.region[i].base + 1136e15146eSJoseph Chen (ulong)lmb->reserved.region[i].size, 114ffa8f8b7SJoseph Chen (ulong)lmb->reserved.region[i].size); 115ffa8f8b7SJoseph Chen } 116ffa8f8b7SJoseph Chen 117ffa8f8b7SJoseph Chen printf("\n reserved.core.total = 0x%08lx (%ld MiB. %ld KiB)\n", 118ffa8f8b7SJoseph Chen (ulong)reserved_size, 119ffa8f8b7SJoseph Chen SIZE_MB((ulong)reserved_size), 120ffa8f8b7SJoseph Chen SIZE_KB((ulong)reserved_size)); 1216e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n\n"); 122ffa8f8b7SJoseph Chen } 123ffa8f8b7SJoseph Chen 1246e15146eSJoseph Chen static inline int sysmem_is_overlap(phys_addr_t base1, phys_size_t size1, 125ffa8f8b7SJoseph Chen phys_addr_t base2, phys_size_t size2) 126ffa8f8b7SJoseph Chen { 127ffa8f8b7SJoseph Chen return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); 128ffa8f8b7SJoseph Chen } 129ffa8f8b7SJoseph Chen 1306e15146eSJoseph Chen static int sysmem_add(phys_addr_t base, phys_size_t size) 131ffa8f8b7SJoseph Chen { 132ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 133ffa8f8b7SJoseph Chen int ret; 134ffa8f8b7SJoseph Chen 1356e15146eSJoseph Chen if (!size) 1366e15146eSJoseph Chen return -EINVAL; 137ffa8f8b7SJoseph Chen 138ffa8f8b7SJoseph Chen ret = lmb_add(&sysmem->lmb, base, size); 139ffa8f8b7SJoseph Chen if (ret < 0) 1406e15146eSJoseph Chen SYSMEM_E("Failed to add sysmem at 0x%08lx for 0x%08lx size\n", 141ffa8f8b7SJoseph Chen (ulong)base, (ulong)size); 142ffa8f8b7SJoseph Chen 143ffa8f8b7SJoseph Chen return (ret >= 0) ? 0 : ret; 144ffa8f8b7SJoseph Chen } 145ffa8f8b7SJoseph Chen 1466e15146eSJoseph Chen static const char *sysmem_alias2name(const char *name, int *id) 147ffa8f8b7SJoseph Chen { 1486e15146eSJoseph Chen const char *alias; 1496e15146eSJoseph Chen int n, i, j; 1506e15146eSJoseph Chen int match = 0; 151ffa8f8b7SJoseph Chen 1526e15146eSJoseph Chen for (i = 0; i < MEMBLK_ID_MAX; i++) { 1536e15146eSJoseph Chen /* Pirmary name */ 1546e15146eSJoseph Chen if (mem_attr[i].name && !strcasecmp(mem_attr[i].name, name)) { 1556e15146eSJoseph Chen match = 1; 1566e15146eSJoseph Chen goto finish; 157ffa8f8b7SJoseph Chen } 158ffa8f8b7SJoseph Chen 1596e15146eSJoseph Chen /* Alias name */ 1606e15146eSJoseph Chen alias = mem_attr[i].alias[0]; 1616e15146eSJoseph Chen if (!alias) 1626e15146eSJoseph Chen continue; 1636e15146eSJoseph Chen 1646e15146eSJoseph Chen n = ARRAY_SIZE(mem_attr[i].alias); 1656e15146eSJoseph Chen for (j = 0; j < n; j++, alias++) { 1666e15146eSJoseph Chen if (alias && !strcasecmp(alias, name)) { 1676e15146eSJoseph Chen match = 1; 1686e15146eSJoseph Chen goto finish; 1696e15146eSJoseph Chen } 170ffa8f8b7SJoseph Chen } 171ffa8f8b7SJoseph Chen } 172ffa8f8b7SJoseph Chen 1736e15146eSJoseph Chen finish: 1746e15146eSJoseph Chen if (match) { 1756e15146eSJoseph Chen *id = i; 1766e15146eSJoseph Chen return mem_attr[i].name; 177ffa8f8b7SJoseph Chen } 178ffa8f8b7SJoseph Chen 1796e15146eSJoseph Chen return name; 180ffa8f8b7SJoseph Chen } 181ffa8f8b7SJoseph Chen 1826e15146eSJoseph Chen static void *sysmem_alloc_align_base(enum memblk_id id, 1836e15146eSJoseph Chen const char *mem_name, 184ffa8f8b7SJoseph Chen phys_addr_t base, 185ffa8f8b7SJoseph Chen phys_size_t size, 186ffa8f8b7SJoseph Chen ulong align) 187ffa8f8b7SJoseph Chen { 188ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 1896e15146eSJoseph Chen struct memblk_attr attr; 1906e15146eSJoseph Chen struct memblock *mem; 1916e15146eSJoseph Chen struct memcheck *check; 192ffa8f8b7SJoseph Chen struct list_head *node; 1936e15146eSJoseph Chen const char *name; 194ffa8f8b7SJoseph Chen phys_addr_t paddr; 195ffa8f8b7SJoseph Chen phys_addr_t alloc_base; 196ffa8f8b7SJoseph Chen phys_size_t alloc_size; 197305d8903SJoseph Chen phys_addr_t bank_base; 198305d8903SJoseph Chen phys_size_t bank_size; 199305d8903SJoseph Chen bool req_overlap = false; /* Only for kernel reserved-memory */ 200305d8903SJoseph Chen int i; 201ffa8f8b7SJoseph Chen 202ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 203efda1f1dSJoseph Chen goto out; 204ffa8f8b7SJoseph Chen 2056e15146eSJoseph Chen if (id == MEMBLK_ID_BY_NAME || id == MEMBLK_ID_FDT_RESV) { 2066e15146eSJoseph Chen if (!mem_name) { 207ffa8f8b7SJoseph Chen SYSMEM_E("NULL name for alloc sysmem\n"); 208efda1f1dSJoseph Chen goto out; 2096e15146eSJoseph Chen } else if (id == MEMBLK_ID_FDT_RESV) { 210efda1f1dSJoseph Chen 211efda1f1dSJoseph Chen /* 212efda1f1dSJoseph Chen * Allow fdt reserved memory to overlap with the region 213efda1f1dSJoseph Chen * only used in U-Boot, like: stack, fastboot, u-boot... 214efda1f1dSJoseph Chen * these regions are marked as M_ATTR_OVERLAP in flags. 215efda1f1dSJoseph Chen * 216efda1f1dSJoseph Chen * Here we check whether it overlaps with others, if 217efda1f1dSJoseph Chen * so, set req_overlap as true. 218efda1f1dSJoseph Chen */ 219305d8903SJoseph Chen for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 220305d8903SJoseph Chen if (!gd->bd->bi_dram[i].size) 221305d8903SJoseph Chen continue; 222305d8903SJoseph Chen 223305d8903SJoseph Chen bank_base = gd->bd->bi_dram[i].start; 224305d8903SJoseph Chen bank_size = gd->bd->bi_dram[i].size; 225305d8903SJoseph Chen if (sysmem_is_overlap(base, size, 226305d8903SJoseph Chen bank_base, bank_size)) { 2276e15146eSJoseph Chen req_overlap = true; 228305d8903SJoseph Chen break; 229305d8903SJoseph Chen } 230305d8903SJoseph Chen } 231305d8903SJoseph Chen 232efda1f1dSJoseph Chen /* 233efda1f1dSJoseph Chen * If this request region is out size of all available 234efda1f1dSJoseph Chen * region, ignore and return success. 235efda1f1dSJoseph Chen */ 236305d8903SJoseph Chen if (!req_overlap) 2376e15146eSJoseph Chen return (void *)base; 2386e15146eSJoseph Chen } 239efda1f1dSJoseph Chen 240efda1f1dSJoseph Chen /* Find name, id and attr by outer mem_name */ 2416e15146eSJoseph Chen name = sysmem_alias2name(mem_name, (int *)&id); 2426e15146eSJoseph Chen attr = mem_attr[id]; 243a90f2861SJoseph Chen if (!attr.name) 244a90f2861SJoseph Chen attr.name = strdup(name); 2456e15146eSJoseph Chen } else if (id > MEMBLK_ID_UNK && id < MEMBLK_ID_MAX) { 2466e15146eSJoseph Chen attr = mem_attr[id]; 2476e15146eSJoseph Chen name = attr.name; 248f6e15301SJoseph Chen 249f6e15301SJoseph Chen /* 250f6e15301SJoseph Chen * Fixup base and place right after U-Boot stack, adding a lot 251f6e15301SJoseph Chen * of space(4KB) maybe safer. 252f6e15301SJoseph Chen */ 253f6e15301SJoseph Chen if ((id == MEMBLK_ID_AVB_ANDROID) && 254f6e15301SJoseph Chen (base == SYSMEM_ALLOC_ANYWHERE)) 255f6e15301SJoseph Chen base = gd->start_addr_sp - 256f6e15301SJoseph Chen CONFIG_SYS_STACK_SIZE - size - 0x1000; 2576e15146eSJoseph Chen } else { 2586e15146eSJoseph Chen SYSMEM_E("Unsupport memblk id %d for alloc sysmem\n", id); 259efda1f1dSJoseph Chen goto out; 2606e15146eSJoseph Chen } 2616e15146eSJoseph Chen 2626e15146eSJoseph Chen if (!size) { 2636e15146eSJoseph Chen SYSMEM_E("\"%s\" size is 0 for alloc sysmem\n", name); 264efda1f1dSJoseph Chen goto out; 265ffa8f8b7SJoseph Chen } 266ffa8f8b7SJoseph Chen 267727ebf6dSJoseph Chen if (!IS_ALIGNED(base, 4)) { 2686e15146eSJoseph Chen SYSMEM_E("\"%s\" base=0x%08lx is not 4-byte aligned\n", 2696e15146eSJoseph Chen name, (ulong)base); 270efda1f1dSJoseph Chen goto out; 271727ebf6dSJoseph Chen } 272727ebf6dSJoseph Chen 273727ebf6dSJoseph Chen /* Must be 4-byte aligned */ 274727ebf6dSJoseph Chen size = ALIGN(size, 4); 275727ebf6dSJoseph Chen 2766e15146eSJoseph Chen SYSMEM_D("Enter alloc: \"%s\" 0x%08lx - 0x%08lx\n", 2776e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size)); 2786e15146eSJoseph Chen 279ffa8f8b7SJoseph Chen /* Already allocated ? */ 280ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 2816e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 2826e15146eSJoseph Chen SYSMEM_D("Has allcated: %s, 0x%08lx - 0x%08lx\n", 2836e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 2846e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 2856e15146eSJoseph Chen if (!strcmp(mem->attr.name, name)) { 286efda1f1dSJoseph Chen /* Allow double alloc for same but smaller region */ 2872cb995bcSJoseph Chen if (mem->base <= base && mem->size >= size) 2882cb995bcSJoseph Chen return (void *)base; 2892cb995bcSJoseph Chen 290ffa8f8b7SJoseph Chen SYSMEM_E("Failed to double alloc for existence \"%s\"\n", name); 291efda1f1dSJoseph Chen goto out; 2926e15146eSJoseph Chen } else if (sysmem_is_overlap(mem->base, mem->size, base, size)) { 293efda1f1dSJoseph Chen /* 294efda1f1dSJoseph Chen * If this new alloc region expects overlap and the old 295efda1f1dSJoseph Chen * region is also allowed to be overlap, just do reserve. 296efda1f1dSJoseph Chen */ 2976e15146eSJoseph Chen if (req_overlap && mem->attr.flags & M_ATTR_OVERLAP) { 2986e15146eSJoseph Chen if (lmb_reserve(&sysmem->lmb, base, size)) 2996e15146eSJoseph Chen SYSMEM_E("Failed to overlap alloc \"%s\" " 3006e15146eSJoseph Chen "at 0x%08lx - 0x%08lx\n", 3016e15146eSJoseph Chen name, (ulong)base, 3026e15146eSJoseph Chen (ulong)(base + size)); 3036e15146eSJoseph Chen return (void *)base; 3046e15146eSJoseph Chen } 3056e15146eSJoseph Chen 3066e15146eSJoseph Chen SYSMEM_E("\"%s\" (0x%08lx - 0x%08lx) alloc is " 3076e15146eSJoseph Chen "overlap with existence \"%s\" (0x%08lx - " 3086e15146eSJoseph Chen "0x%08lx)\n", 3096e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size), 3106e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 3116e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 312efda1f1dSJoseph Chen goto out; 313ffa8f8b7SJoseph Chen } 314ffa8f8b7SJoseph Chen } 315ffa8f8b7SJoseph Chen 3166e15146eSJoseph Chen /* Add overflow check magic ? */ 3176e15146eSJoseph Chen if (attr.flags & M_ATTR_OFC) 318ffa8f8b7SJoseph Chen alloc_size = size + sizeof(*check); 3196e15146eSJoseph Chen else 3206e15146eSJoseph Chen alloc_size = size; 3216e15146eSJoseph Chen 3226e15146eSJoseph Chen /* Alloc anywhere ? */ 323ffa8f8b7SJoseph Chen if (base == SYSMEM_ALLOC_ANYWHERE) 324ffa8f8b7SJoseph Chen alloc_base = base; 325ffa8f8b7SJoseph Chen else 326ffa8f8b7SJoseph Chen alloc_base = base + alloc_size; /* LMB is align down alloc mechanism */ 327ffa8f8b7SJoseph Chen 328ffa8f8b7SJoseph Chen paddr = lmb_alloc_base(&sysmem->lmb, alloc_size, align, alloc_base); 329ffa8f8b7SJoseph Chen if (paddr) { 330ffa8f8b7SJoseph Chen if ((paddr == base) || (base == SYSMEM_ALLOC_ANYWHERE)) { 3316e15146eSJoseph Chen mem = malloc(sizeof(*mem)); 3326e15146eSJoseph Chen if (!mem) { 333ffa8f8b7SJoseph Chen SYSMEM_E("No memory for \"%s\" alloc sysmem\n", name); 334efda1f1dSJoseph Chen goto out; 335ffa8f8b7SJoseph Chen } 336ffa8f8b7SJoseph Chen 3376e15146eSJoseph Chen mem->base = paddr; 3386e15146eSJoseph Chen mem->size = alloc_size; 3396e15146eSJoseph Chen mem->attr = attr; 340ffa8f8b7SJoseph Chen sysmem->allocated_cnt++; 3416e15146eSJoseph Chen list_add_tail(&mem->node, &sysmem->allocated_head); 342ffa8f8b7SJoseph Chen 343efda1f1dSJoseph Chen /* Add overflow check magic */ 3446e15146eSJoseph Chen if (mem->attr.flags & M_ATTR_OFC) { 3456e15146eSJoseph Chen check = (struct memcheck *)(paddr + size); 346ffa8f8b7SJoseph Chen check->magic = SYSMEM_MAGIC; 3476e15146eSJoseph Chen } else if (mem->attr.flags & M_ATTR_HOFC) { 3486e15146eSJoseph Chen check = (struct memcheck *)(paddr - sizeof(*check)); 3496e15146eSJoseph Chen check->magic = SYSMEM_MAGIC; 3506e15146eSJoseph Chen } 351ffa8f8b7SJoseph Chen } else { 3526e15146eSJoseph Chen SYSMEM_E("Failed to alloc \"%s\" expect at 0x%08lx - 0x%08lx " 3536e15146eSJoseph Chen "but at 0x%08lx - x%08lx\n", 3546e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size), 3556e15146eSJoseph Chen (ulong)paddr, (ulong)(paddr + size)); 356efda1f1dSJoseph Chen /* Free what we don't want allocated region */ 3573bee194fSJoseph Chen if (lmb_free(&sysmem->lmb, paddr, alloc_size) < 0) 3586e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\"\n", name); 3596e15146eSJoseph Chen 360efda1f1dSJoseph Chen goto out; 361ffa8f8b7SJoseph Chen } 362ffa8f8b7SJoseph Chen } else { 3636e15146eSJoseph Chen SYSMEM_E("Failed to alloc \"%s\" at 0x%08lx - 0x%08lx\n", 3646e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size)); 365*661cbb0bSJoseph Chen goto out; 366ffa8f8b7SJoseph Chen } 367ffa8f8b7SJoseph Chen 3686e15146eSJoseph Chen SYSMEM_D("Exit alloc: \"%s\", paddr=0x%08lx, size=0x%08lx, align=0x%x, anywhere=%d\n", 369ffa8f8b7SJoseph Chen name, (ulong)paddr, (ulong)size, (u32)align, !base); 370ffa8f8b7SJoseph Chen 371ffa8f8b7SJoseph Chen return (void *)paddr; 372efda1f1dSJoseph Chen 373efda1f1dSJoseph Chen out: 374efda1f1dSJoseph Chen return (attr.flags & M_ATTR_PEEK) ? (void *)base : NULL; 375ffa8f8b7SJoseph Chen } 376ffa8f8b7SJoseph Chen 377dcb404a6SJoseph Chen void *sysmem_alloc(enum memblk_id id, phys_size_t size) 378dcb404a6SJoseph Chen { 379dcb404a6SJoseph Chen void *paddr; 380dcb404a6SJoseph Chen 381dcb404a6SJoseph Chen paddr = sysmem_alloc_align_base(id, 382dcb404a6SJoseph Chen NULL, 383dcb404a6SJoseph Chen SYSMEM_ALLOC_ANYWHERE, 384dcb404a6SJoseph Chen size, 385dcb404a6SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 386dcb404a6SJoseph Chen if (!paddr) 387dcb404a6SJoseph Chen sysmem_dump(); 388dcb404a6SJoseph Chen 389dcb404a6SJoseph Chen return paddr; 390dcb404a6SJoseph Chen } 391dcb404a6SJoseph Chen 3926e15146eSJoseph Chen void *sysmem_alloc_base(enum memblk_id id, phys_addr_t base, phys_size_t size) 393ffa8f8b7SJoseph Chen { 3946e15146eSJoseph Chen void *paddr; 395ffa8f8b7SJoseph Chen 3966e15146eSJoseph Chen paddr = sysmem_alloc_align_base(id, 3976e15146eSJoseph Chen NULL, 398ffa8f8b7SJoseph Chen base, 399ffa8f8b7SJoseph Chen size, 400ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 4016e15146eSJoseph Chen if (!paddr) 4026e15146eSJoseph Chen sysmem_dump(); 4036e15146eSJoseph Chen 4046e15146eSJoseph Chen return paddr; 405ffa8f8b7SJoseph Chen } 406ffa8f8b7SJoseph Chen 4076e15146eSJoseph Chen void *sysmem_alloc_base_by_name(const char *name, 4086e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 409ffa8f8b7SJoseph Chen { 4106e15146eSJoseph Chen void *paddr; 4116e15146eSJoseph Chen 4126e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_BY_NAME, 4136e15146eSJoseph Chen name, 4146e15146eSJoseph Chen base, 415ffa8f8b7SJoseph Chen size, 416ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 4176e15146eSJoseph Chen if (!paddr) 4186e15146eSJoseph Chen sysmem_dump(); 4196e15146eSJoseph Chen 4206e15146eSJoseph Chen return paddr; 4216e15146eSJoseph Chen } 4226e15146eSJoseph Chen 4236e15146eSJoseph Chen void *sysmem_fdt_reserve_alloc_base(const char *name, 4246e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 4256e15146eSJoseph Chen { 4266e15146eSJoseph Chen void *paddr; 4276e15146eSJoseph Chen 4286e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_FDT_RESV, 4296e15146eSJoseph Chen name, 4306e15146eSJoseph Chen base, 4316e15146eSJoseph Chen size, 4326e15146eSJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 4336e15146eSJoseph Chen if (!paddr) 4346e15146eSJoseph Chen sysmem_dump(); 4356e15146eSJoseph Chen 4366e15146eSJoseph Chen return paddr; 437ffa8f8b7SJoseph Chen } 438ffa8f8b7SJoseph Chen 4393bee194fSJoseph Chen bool sysmem_can_alloc(phys_size_t base, phys_size_t size) 4403bee194fSJoseph Chen { 4413bee194fSJoseph Chen struct sysmem *sysmem = &plat_sysmem; 4423bee194fSJoseph Chen phys_addr_t alloc_base; 4433bee194fSJoseph Chen phys_addr_t paddr; 4443bee194fSJoseph Chen int ret; 4453bee194fSJoseph Chen 4463bee194fSJoseph Chen if (!sysmem_has_init()) 4473bee194fSJoseph Chen return false; 4483bee194fSJoseph Chen 4493bee194fSJoseph Chen /* LMB is align down alloc mechanism */ 4503bee194fSJoseph Chen alloc_base = base + size; 4513bee194fSJoseph Chen paddr = __lmb_alloc_base(&sysmem->lmb, 4523bee194fSJoseph Chen size, 4533bee194fSJoseph Chen SYSMEM_ALLOC_NO_ALIGN, 4543bee194fSJoseph Chen alloc_base); 4553bee194fSJoseph Chen if (paddr) { 4563bee194fSJoseph Chen /* If free failed, return false */ 4573bee194fSJoseph Chen ret = lmb_free(&sysmem->lmb, base, size); 4583bee194fSJoseph Chen if (ret < 0) { 4593bee194fSJoseph Chen SYSMEM_E("Can't free at 0x%08lx - 0x%08lx, ret=%d\n", 4603bee194fSJoseph Chen (ulong)base, (ulong)(base + size), ret); 4613bee194fSJoseph Chen return false; 4623bee194fSJoseph Chen } 4633bee194fSJoseph Chen } else { 4643bee194fSJoseph Chen SYSMEM_D("Can't alloc at 0x%08lx - 0x%08lx\n", 4653bee194fSJoseph Chen (ulong)base, (ulong)(base + size)); 4663bee194fSJoseph Chen } 4673bee194fSJoseph Chen 4683bee194fSJoseph Chen return (paddr == base) ? true : false; 4693bee194fSJoseph Chen } 4703bee194fSJoseph Chen 471ffa8f8b7SJoseph Chen int sysmem_free(phys_addr_t base) 472ffa8f8b7SJoseph Chen { 473ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 4746e15146eSJoseph Chen struct memblock *mem; 475ffa8f8b7SJoseph Chen struct list_head *node; 4766e15146eSJoseph Chen int ret, found = 0; 477ffa8f8b7SJoseph Chen 478ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 479ffa8f8b7SJoseph Chen return -ENOSYS; 480ffa8f8b7SJoseph Chen 481ffa8f8b7SJoseph Chen /* Find existence */ 482ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 4836e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 4846e15146eSJoseph Chen if (mem->base == base) { 485ffa8f8b7SJoseph Chen found = 1; 486ffa8f8b7SJoseph Chen break; 487ffa8f8b7SJoseph Chen } 488ffa8f8b7SJoseph Chen } 489ffa8f8b7SJoseph Chen 490ffa8f8b7SJoseph Chen if (!found) { 4916e15146eSJoseph Chen SYSMEM_E("Failed to free no allocated sysmem at 0x%08lx\n", 4926e15146eSJoseph Chen (ulong)base); 493ffa8f8b7SJoseph Chen return -EINVAL; 494ffa8f8b7SJoseph Chen } 495ffa8f8b7SJoseph Chen 4966e15146eSJoseph Chen ret = lmb_free(&sysmem->lmb, mem->base, mem->size); 497ffa8f8b7SJoseph Chen if (ret >= 0) { 4986e15146eSJoseph Chen SYSMEM_D("Free: \"%s\" 0x%08lx - 0x%08lx\n", 4996e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 5006e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 501ffa8f8b7SJoseph Chen sysmem->allocated_cnt--; 5026e15146eSJoseph Chen list_del(&mem->node); 5036e15146eSJoseph Chen free(mem); 504ffa8f8b7SJoseph Chen } else { 5056e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\" at 0x%08lx\n", 5066e15146eSJoseph Chen mem->attr.name, (ulong)base); 507ffa8f8b7SJoseph Chen } 508ffa8f8b7SJoseph Chen 509ffa8f8b7SJoseph Chen return (ret >= 0) ? 0 : ret; 510ffa8f8b7SJoseph Chen } 511ffa8f8b7SJoseph Chen 5126e15146eSJoseph Chen int sysmem_initr(void) 5136e15146eSJoseph Chen { 5146e15146eSJoseph Chen return sysmem_init(); 5156e15146eSJoseph Chen } 5166e15146eSJoseph Chen 517ffa8f8b7SJoseph Chen int sysmem_init(void) 518ffa8f8b7SJoseph Chen { 519ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 520ffa8f8b7SJoseph Chen phys_addr_t mem_start; 521ffa8f8b7SJoseph Chen phys_size_t mem_size; 522ffa8f8b7SJoseph Chen int ret; 523ffa8f8b7SJoseph Chen 524ffa8f8b7SJoseph Chen lmb_init(&sysmem->lmb); 525ffa8f8b7SJoseph Chen INIT_LIST_HEAD(&sysmem->allocated_head); 526ffa8f8b7SJoseph Chen sysmem->allocated_cnt = 0; 5276e15146eSJoseph Chen if (gd->flags & GD_FLG_RELOC) { 5286e15146eSJoseph Chen sysmem->has_initr = true; 5296e15146eSJoseph Chen } else { 5306e15146eSJoseph Chen SYSMEM_I("init\n"); 5316e15146eSJoseph Chen sysmem->has_initf = true; 5326e15146eSJoseph Chen } 533ffa8f8b7SJoseph Chen 534ffa8f8b7SJoseph Chen /* Add all available system memory */ 535ffa8f8b7SJoseph Chen #ifdef CONFIG_NR_DRAM_BANKS 536ffa8f8b7SJoseph Chen int i; 537ffa8f8b7SJoseph Chen 538ffa8f8b7SJoseph Chen for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 5396e15146eSJoseph Chen if (!gd->bd->bi_dram[i].size) 5406e15146eSJoseph Chen continue; 5416e15146eSJoseph Chen 542ffa8f8b7SJoseph Chen ret = sysmem_add(gd->bd->bi_dram[i].start, 543ffa8f8b7SJoseph Chen gd->bd->bi_dram[i].size); 544ffa8f8b7SJoseph Chen if (ret) { 545ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bi_dram[%d]\n", i); 5466e15146eSJoseph Chen goto fail; 547ffa8f8b7SJoseph Chen } 548ffa8f8b7SJoseph Chen } 549ffa8f8b7SJoseph Chen #else 550ffa8f8b7SJoseph Chen mem_start = env_get_bootm_low(); 551ffa8f8b7SJoseph Chen mem_size = env_get_bootm_size(); 552ffa8f8b7SJoseph Chen ret = sysmem_add(mem_start, mem_size); 553ffa8f8b7SJoseph Chen if (ret) { 554ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bootm_low/size\n"); 5556e15146eSJoseph Chen goto fail; 556ffa8f8b7SJoseph Chen } 557ffa8f8b7SJoseph Chen #endif 558ffa8f8b7SJoseph Chen /* Reserved for board */ 559ffa8f8b7SJoseph Chen ret = board_sysmem_reserve(sysmem); 560ffa8f8b7SJoseph Chen if (ret) { 561ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for board\n"); 5626e15146eSJoseph Chen goto fail; 563ffa8f8b7SJoseph Chen } 564ffa8f8b7SJoseph Chen 5656e15146eSJoseph Chen /* Reserved for U-boot framework: 'reserve_xxx()' */ 5666e15146eSJoseph Chen mem_start = gd->start_addr_sp; 567ffa8f8b7SJoseph Chen mem_size = gd->ram_top - mem_start; 5686e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_UBOOT, mem_start, mem_size)) { 569ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for U-Boot framework\n"); 5706e15146eSJoseph Chen ret = -ENOMEM; 5716e15146eSJoseph Chen goto fail; 572ffa8f8b7SJoseph Chen } 573ffa8f8b7SJoseph Chen 5746e15146eSJoseph Chen /* Reserved for U-Boot stack */ 5756e15146eSJoseph Chen mem_start = gd->start_addr_sp - CONFIG_SYS_STACK_SIZE; 5766e15146eSJoseph Chen mem_size = CONFIG_SYS_STACK_SIZE; 5776e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_STACK, mem_start, mem_size)) { 5786e15146eSJoseph Chen SYSMEM_E("Failed to reserve sysmem for stack\n"); 5796e15146eSJoseph Chen ret = -ENOMEM; 5806e15146eSJoseph Chen goto fail; 5816e15146eSJoseph Chen } 582ffa8f8b7SJoseph Chen 583ffa8f8b7SJoseph Chen return 0; 5846e15146eSJoseph Chen 5856e15146eSJoseph Chen fail: 5866e15146eSJoseph Chen if (ret && !(gd->flags & GD_FLG_RELOC)) { 5876e15146eSJoseph Chen sysmem_dump(); 5886e15146eSJoseph Chen SYSMEM_W("Maybe malloc size %d MiB is too large?\n\n", 5896e15146eSJoseph Chen SIZE_MB(CONFIG_SYS_MALLOC_LEN)); 5906e15146eSJoseph Chen } 5916e15146eSJoseph Chen 5926e15146eSJoseph Chen return ret; 593ffa8f8b7SJoseph Chen } 594ffa8f8b7SJoseph Chen 595ffa8f8b7SJoseph Chen __weak int board_sysmem_reserve(struct sysmem *sysmem) 596ffa8f8b7SJoseph Chen { 597ffa8f8b7SJoseph Chen /* please define platform specific board_sysmem_reserve() */ 598ffa8f8b7SJoseph Chen return 0; 599ffa8f8b7SJoseph Chen } 600ffa8f8b7SJoseph Chen 6016e15146eSJoseph Chen static int do_dump_sysmem(cmd_tbl_t *cmdtp, int flag, 6026e15146eSJoseph Chen int argc, char *const argv[]) 603ffa8f8b7SJoseph Chen { 6046e15146eSJoseph Chen sysmem_dump(); 605ffa8f8b7SJoseph Chen return 0; 606ffa8f8b7SJoseph Chen } 6076e15146eSJoseph Chen 6086e15146eSJoseph Chen U_BOOT_CMD( 6096e15146eSJoseph Chen dump_sysmem, 1, 1, do_dump_sysmem, 6106e15146eSJoseph Chen "Dump sysmem layout", 6116e15146eSJoseph Chen "" 6126e15146eSJoseph Chen ); 613