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; 2486e15146eSJoseph Chen } else { 2496e15146eSJoseph Chen SYSMEM_E("Unsupport memblk id %d for alloc sysmem\n", id); 250efda1f1dSJoseph Chen goto out; 2516e15146eSJoseph Chen } 2526e15146eSJoseph Chen 2536e15146eSJoseph Chen if (!size) { 2546e15146eSJoseph Chen SYSMEM_E("\"%s\" size is 0 for alloc sysmem\n", name); 255efda1f1dSJoseph Chen goto out; 256ffa8f8b7SJoseph Chen } 257ffa8f8b7SJoseph Chen 258727ebf6dSJoseph Chen if (!IS_ALIGNED(base, 4)) { 2596e15146eSJoseph Chen SYSMEM_E("\"%s\" base=0x%08lx is not 4-byte aligned\n", 2606e15146eSJoseph Chen name, (ulong)base); 261efda1f1dSJoseph Chen goto out; 262727ebf6dSJoseph Chen } 263727ebf6dSJoseph Chen 264727ebf6dSJoseph Chen /* Must be 4-byte aligned */ 265727ebf6dSJoseph Chen size = ALIGN(size, 4); 266727ebf6dSJoseph Chen 2676e15146eSJoseph Chen SYSMEM_D("Enter alloc: \"%s\" 0x%08lx - 0x%08lx\n", 2686e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size)); 2696e15146eSJoseph Chen 270ffa8f8b7SJoseph Chen /* Already allocated ? */ 271ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 2726e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 2736e15146eSJoseph Chen SYSMEM_D("Has allcated: %s, 0x%08lx - 0x%08lx\n", 2746e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 2756e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 2766e15146eSJoseph Chen if (!strcmp(mem->attr.name, name)) { 277efda1f1dSJoseph Chen /* Allow double alloc for same but smaller region */ 2782cb995bcSJoseph Chen if (mem->base <= base && mem->size >= size) 2792cb995bcSJoseph Chen return (void *)base; 2802cb995bcSJoseph Chen 281ffa8f8b7SJoseph Chen SYSMEM_E("Failed to double alloc for existence \"%s\"\n", name); 282efda1f1dSJoseph Chen goto out; 2836e15146eSJoseph Chen } else if (sysmem_is_overlap(mem->base, mem->size, base, size)) { 284efda1f1dSJoseph Chen /* 285efda1f1dSJoseph Chen * If this new alloc region expects overlap and the old 286efda1f1dSJoseph Chen * region is also allowed to be overlap, just do reserve. 287efda1f1dSJoseph Chen */ 2886e15146eSJoseph Chen if (req_overlap && mem->attr.flags & M_ATTR_OVERLAP) { 2896e15146eSJoseph Chen if (lmb_reserve(&sysmem->lmb, base, size)) 2906e15146eSJoseph Chen SYSMEM_E("Failed to overlap alloc \"%s\" " 2916e15146eSJoseph Chen "at 0x%08lx - 0x%08lx\n", 2926e15146eSJoseph Chen name, (ulong)base, 2936e15146eSJoseph Chen (ulong)(base + size)); 2946e15146eSJoseph Chen return (void *)base; 2956e15146eSJoseph Chen } 2966e15146eSJoseph Chen 2976e15146eSJoseph Chen SYSMEM_E("\"%s\" (0x%08lx - 0x%08lx) alloc is " 2986e15146eSJoseph Chen "overlap with existence \"%s\" (0x%08lx - " 2996e15146eSJoseph Chen "0x%08lx)\n", 3006e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size), 3016e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 3026e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 303efda1f1dSJoseph Chen goto out; 304ffa8f8b7SJoseph Chen } 305ffa8f8b7SJoseph Chen } 306ffa8f8b7SJoseph Chen 3076e15146eSJoseph Chen /* Add overflow check magic ? */ 3086e15146eSJoseph Chen if (attr.flags & M_ATTR_OFC) 309ffa8f8b7SJoseph Chen alloc_size = size + sizeof(*check); 3106e15146eSJoseph Chen else 3116e15146eSJoseph Chen alloc_size = size; 3126e15146eSJoseph Chen 3136e15146eSJoseph Chen /* Alloc anywhere ? */ 314ffa8f8b7SJoseph Chen if (base == SYSMEM_ALLOC_ANYWHERE) 315ffa8f8b7SJoseph Chen alloc_base = base; 316ffa8f8b7SJoseph Chen else 317ffa8f8b7SJoseph Chen alloc_base = base + alloc_size; /* LMB is align down alloc mechanism */ 318ffa8f8b7SJoseph Chen 319ffa8f8b7SJoseph Chen paddr = lmb_alloc_base(&sysmem->lmb, alloc_size, align, alloc_base); 320ffa8f8b7SJoseph Chen if (paddr) { 321ffa8f8b7SJoseph Chen if ((paddr == base) || (base == SYSMEM_ALLOC_ANYWHERE)) { 3226e15146eSJoseph Chen mem = malloc(sizeof(*mem)); 3236e15146eSJoseph Chen if (!mem) { 324ffa8f8b7SJoseph Chen SYSMEM_E("No memory for \"%s\" alloc sysmem\n", name); 325efda1f1dSJoseph Chen goto out; 326ffa8f8b7SJoseph Chen } 327ffa8f8b7SJoseph Chen 3286e15146eSJoseph Chen mem->base = paddr; 3296e15146eSJoseph Chen mem->size = alloc_size; 3306e15146eSJoseph Chen mem->attr = attr; 331ffa8f8b7SJoseph Chen sysmem->allocated_cnt++; 3326e15146eSJoseph Chen list_add_tail(&mem->node, &sysmem->allocated_head); 333ffa8f8b7SJoseph Chen 334efda1f1dSJoseph Chen /* Add overflow check magic */ 3356e15146eSJoseph Chen if (mem->attr.flags & M_ATTR_OFC) { 3366e15146eSJoseph Chen check = (struct memcheck *)(paddr + size); 337ffa8f8b7SJoseph Chen check->magic = SYSMEM_MAGIC; 3386e15146eSJoseph Chen } else if (mem->attr.flags & M_ATTR_HOFC) { 3396e15146eSJoseph Chen check = (struct memcheck *)(paddr - sizeof(*check)); 3406e15146eSJoseph Chen check->magic = SYSMEM_MAGIC; 3416e15146eSJoseph Chen } 342ffa8f8b7SJoseph Chen } else { 3436e15146eSJoseph Chen SYSMEM_E("Failed to alloc \"%s\" expect at 0x%08lx - 0x%08lx " 3446e15146eSJoseph Chen "but at 0x%08lx - x%08lx\n", 3456e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size), 3466e15146eSJoseph Chen (ulong)paddr, (ulong)(paddr + size)); 347efda1f1dSJoseph Chen /* Free what we don't want allocated region */ 3486e15146eSJoseph Chen if (lmb_free(&sysmem->lmb, paddr, alloc_size)) 3496e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\"\n", name); 3506e15146eSJoseph Chen 351efda1f1dSJoseph Chen goto out; 352ffa8f8b7SJoseph Chen } 353ffa8f8b7SJoseph Chen } else { 3546e15146eSJoseph Chen SYSMEM_E("Failed to alloc \"%s\" at 0x%08lx - 0x%08lx\n", 3556e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size)); 356ffa8f8b7SJoseph Chen } 357ffa8f8b7SJoseph Chen 3586e15146eSJoseph Chen SYSMEM_D("Exit alloc: \"%s\", paddr=0x%08lx, size=0x%08lx, align=0x%x, anywhere=%d\n", 359ffa8f8b7SJoseph Chen name, (ulong)paddr, (ulong)size, (u32)align, !base); 360ffa8f8b7SJoseph Chen 361ffa8f8b7SJoseph Chen return (void *)paddr; 362efda1f1dSJoseph Chen 363efda1f1dSJoseph Chen out: 364efda1f1dSJoseph Chen return (attr.flags & M_ATTR_PEEK) ? (void *)base : NULL; 365ffa8f8b7SJoseph Chen } 366ffa8f8b7SJoseph Chen 367*dcb404a6SJoseph Chen void *sysmem_alloc(enum memblk_id id, phys_size_t size) 368*dcb404a6SJoseph Chen { 369*dcb404a6SJoseph Chen void *paddr; 370*dcb404a6SJoseph Chen 371*dcb404a6SJoseph Chen paddr = sysmem_alloc_align_base(id, 372*dcb404a6SJoseph Chen NULL, 373*dcb404a6SJoseph Chen SYSMEM_ALLOC_ANYWHERE, 374*dcb404a6SJoseph Chen size, 375*dcb404a6SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 376*dcb404a6SJoseph Chen if (!paddr) 377*dcb404a6SJoseph Chen sysmem_dump(); 378*dcb404a6SJoseph Chen 379*dcb404a6SJoseph Chen return paddr; 380*dcb404a6SJoseph Chen } 381*dcb404a6SJoseph Chen 3826e15146eSJoseph Chen void *sysmem_alloc_base(enum memblk_id id, phys_addr_t base, phys_size_t size) 383ffa8f8b7SJoseph Chen { 3846e15146eSJoseph Chen void *paddr; 385ffa8f8b7SJoseph Chen 3866e15146eSJoseph Chen paddr = sysmem_alloc_align_base(id, 3876e15146eSJoseph Chen NULL, 388ffa8f8b7SJoseph Chen base, 389ffa8f8b7SJoseph Chen size, 390ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 3916e15146eSJoseph Chen if (!paddr) 3926e15146eSJoseph Chen sysmem_dump(); 3936e15146eSJoseph Chen 3946e15146eSJoseph Chen return paddr; 395ffa8f8b7SJoseph Chen } 396ffa8f8b7SJoseph Chen 3976e15146eSJoseph Chen void *sysmem_alloc_base_by_name(const char *name, 3986e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 399ffa8f8b7SJoseph Chen { 4006e15146eSJoseph Chen void *paddr; 4016e15146eSJoseph Chen 4026e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_BY_NAME, 4036e15146eSJoseph Chen name, 4046e15146eSJoseph Chen base, 405ffa8f8b7SJoseph Chen size, 406ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 4076e15146eSJoseph Chen if (!paddr) 4086e15146eSJoseph Chen sysmem_dump(); 4096e15146eSJoseph Chen 4106e15146eSJoseph Chen return paddr; 4116e15146eSJoseph Chen } 4126e15146eSJoseph Chen 4136e15146eSJoseph Chen void *sysmem_fdt_reserve_alloc_base(const char *name, 4146e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 4156e15146eSJoseph Chen { 4166e15146eSJoseph Chen void *paddr; 4176e15146eSJoseph Chen 4186e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_FDT_RESV, 4196e15146eSJoseph Chen name, 4206e15146eSJoseph Chen base, 4216e15146eSJoseph Chen size, 4226e15146eSJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 4236e15146eSJoseph Chen if (!paddr) 4246e15146eSJoseph Chen sysmem_dump(); 4256e15146eSJoseph Chen 4266e15146eSJoseph Chen return paddr; 427ffa8f8b7SJoseph Chen } 428ffa8f8b7SJoseph Chen 429ffa8f8b7SJoseph Chen int sysmem_free(phys_addr_t base) 430ffa8f8b7SJoseph Chen { 431ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 4326e15146eSJoseph Chen struct memblock *mem; 433ffa8f8b7SJoseph Chen struct list_head *node; 4346e15146eSJoseph Chen int ret, found = 0; 435ffa8f8b7SJoseph Chen 436ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 437ffa8f8b7SJoseph Chen return -ENOSYS; 438ffa8f8b7SJoseph Chen 439ffa8f8b7SJoseph Chen /* Find existence */ 440ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 4416e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 4426e15146eSJoseph Chen if (mem->base == base) { 443ffa8f8b7SJoseph Chen found = 1; 444ffa8f8b7SJoseph Chen break; 445ffa8f8b7SJoseph Chen } 446ffa8f8b7SJoseph Chen } 447ffa8f8b7SJoseph Chen 448ffa8f8b7SJoseph Chen if (!found) { 4496e15146eSJoseph Chen SYSMEM_E("Failed to free no allocated sysmem at 0x%08lx\n", 4506e15146eSJoseph Chen (ulong)base); 451ffa8f8b7SJoseph Chen return -EINVAL; 452ffa8f8b7SJoseph Chen } 453ffa8f8b7SJoseph Chen 4546e15146eSJoseph Chen ret = lmb_free(&sysmem->lmb, mem->base, mem->size); 455ffa8f8b7SJoseph Chen if (ret >= 0) { 4566e15146eSJoseph Chen SYSMEM_D("Free: \"%s\" 0x%08lx - 0x%08lx\n", 4576e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 4586e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 459ffa8f8b7SJoseph Chen sysmem->allocated_cnt--; 4606e15146eSJoseph Chen list_del(&mem->node); 4616e15146eSJoseph Chen free(mem); 462ffa8f8b7SJoseph Chen } else { 4636e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\" at 0x%08lx\n", 4646e15146eSJoseph Chen mem->attr.name, (ulong)base); 465ffa8f8b7SJoseph Chen } 466ffa8f8b7SJoseph Chen 467ffa8f8b7SJoseph Chen return (ret >= 0) ? 0 : ret; 468ffa8f8b7SJoseph Chen } 469ffa8f8b7SJoseph Chen 4706e15146eSJoseph Chen int sysmem_initr(void) 4716e15146eSJoseph Chen { 4726e15146eSJoseph Chen return sysmem_init(); 4736e15146eSJoseph Chen } 4746e15146eSJoseph Chen 475ffa8f8b7SJoseph Chen int sysmem_init(void) 476ffa8f8b7SJoseph Chen { 477ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 478ffa8f8b7SJoseph Chen phys_addr_t mem_start; 479ffa8f8b7SJoseph Chen phys_size_t mem_size; 480ffa8f8b7SJoseph Chen int ret; 481ffa8f8b7SJoseph Chen 482ffa8f8b7SJoseph Chen lmb_init(&sysmem->lmb); 483ffa8f8b7SJoseph Chen INIT_LIST_HEAD(&sysmem->allocated_head); 484ffa8f8b7SJoseph Chen sysmem->allocated_cnt = 0; 4856e15146eSJoseph Chen if (gd->flags & GD_FLG_RELOC) { 4866e15146eSJoseph Chen sysmem->has_initr = true; 4876e15146eSJoseph Chen } else { 4886e15146eSJoseph Chen SYSMEM_I("init\n"); 4896e15146eSJoseph Chen sysmem->has_initf = true; 4906e15146eSJoseph Chen } 491ffa8f8b7SJoseph Chen 492ffa8f8b7SJoseph Chen /* Add all available system memory */ 493ffa8f8b7SJoseph Chen #ifdef CONFIG_NR_DRAM_BANKS 494ffa8f8b7SJoseph Chen int i; 495ffa8f8b7SJoseph Chen 496ffa8f8b7SJoseph Chen for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 4976e15146eSJoseph Chen if (!gd->bd->bi_dram[i].size) 4986e15146eSJoseph Chen continue; 4996e15146eSJoseph Chen 500ffa8f8b7SJoseph Chen ret = sysmem_add(gd->bd->bi_dram[i].start, 501ffa8f8b7SJoseph Chen gd->bd->bi_dram[i].size); 502ffa8f8b7SJoseph Chen if (ret) { 503ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bi_dram[%d]\n", i); 5046e15146eSJoseph Chen goto fail; 505ffa8f8b7SJoseph Chen } 506ffa8f8b7SJoseph Chen } 507ffa8f8b7SJoseph Chen #else 508ffa8f8b7SJoseph Chen mem_start = env_get_bootm_low(); 509ffa8f8b7SJoseph Chen mem_size = env_get_bootm_size(); 510ffa8f8b7SJoseph Chen ret = sysmem_add(mem_start, mem_size); 511ffa8f8b7SJoseph Chen if (ret) { 512ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bootm_low/size\n"); 5136e15146eSJoseph Chen goto fail; 514ffa8f8b7SJoseph Chen } 515ffa8f8b7SJoseph Chen #endif 516ffa8f8b7SJoseph Chen /* Reserved for board */ 517ffa8f8b7SJoseph Chen ret = board_sysmem_reserve(sysmem); 518ffa8f8b7SJoseph Chen if (ret) { 519ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for board\n"); 5206e15146eSJoseph Chen goto fail; 521ffa8f8b7SJoseph Chen } 522ffa8f8b7SJoseph Chen 5236e15146eSJoseph Chen /* Reserved for U-boot framework: 'reserve_xxx()' */ 5246e15146eSJoseph Chen mem_start = gd->start_addr_sp; 525ffa8f8b7SJoseph Chen mem_size = gd->ram_top - mem_start; 5266e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_UBOOT, mem_start, mem_size)) { 527ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for U-Boot framework\n"); 5286e15146eSJoseph Chen ret = -ENOMEM; 5296e15146eSJoseph Chen goto fail; 530ffa8f8b7SJoseph Chen } 531ffa8f8b7SJoseph Chen 5326e15146eSJoseph Chen /* Reserved for U-Boot stack */ 5336e15146eSJoseph Chen mem_start = gd->start_addr_sp - CONFIG_SYS_STACK_SIZE; 5346e15146eSJoseph Chen mem_size = CONFIG_SYS_STACK_SIZE; 5356e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_STACK, mem_start, mem_size)) { 5366e15146eSJoseph Chen SYSMEM_E("Failed to reserve sysmem for stack\n"); 5376e15146eSJoseph Chen ret = -ENOMEM; 5386e15146eSJoseph Chen goto fail; 5396e15146eSJoseph Chen } 540ffa8f8b7SJoseph Chen 541ffa8f8b7SJoseph Chen return 0; 5426e15146eSJoseph Chen 5436e15146eSJoseph Chen fail: 5446e15146eSJoseph Chen if (ret && !(gd->flags & GD_FLG_RELOC)) { 5456e15146eSJoseph Chen sysmem_dump(); 5466e15146eSJoseph Chen SYSMEM_W("Maybe malloc size %d MiB is too large?\n\n", 5476e15146eSJoseph Chen SIZE_MB(CONFIG_SYS_MALLOC_LEN)); 5486e15146eSJoseph Chen } 5496e15146eSJoseph Chen 5506e15146eSJoseph Chen return ret; 551ffa8f8b7SJoseph Chen } 552ffa8f8b7SJoseph Chen 553ffa8f8b7SJoseph Chen __weak int board_sysmem_reserve(struct sysmem *sysmem) 554ffa8f8b7SJoseph Chen { 555ffa8f8b7SJoseph Chen /* please define platform specific board_sysmem_reserve() */ 556ffa8f8b7SJoseph Chen return 0; 557ffa8f8b7SJoseph Chen } 558ffa8f8b7SJoseph Chen 5596e15146eSJoseph Chen static int do_dump_sysmem(cmd_tbl_t *cmdtp, int flag, 5606e15146eSJoseph Chen int argc, char *const argv[]) 561ffa8f8b7SJoseph Chen { 5626e15146eSJoseph Chen sysmem_dump(); 563ffa8f8b7SJoseph Chen return 0; 564ffa8f8b7SJoseph Chen } 5656e15146eSJoseph Chen 5666e15146eSJoseph Chen U_BOOT_CMD( 5676e15146eSJoseph Chen dump_sysmem, 1, 1, do_dump_sysmem, 5686e15146eSJoseph Chen "Dump sysmem layout", 5696e15146eSJoseph Chen "" 5706e15146eSJoseph Chen ); 571