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()) 203*efda1f1dSJoseph 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"); 208*efda1f1dSJoseph Chen goto out; 2096e15146eSJoseph Chen } else if (id == MEMBLK_ID_FDT_RESV) { 210*efda1f1dSJoseph Chen 211*efda1f1dSJoseph Chen /* 212*efda1f1dSJoseph Chen * Allow fdt reserved memory to overlap with the region 213*efda1f1dSJoseph Chen * only used in U-Boot, like: stack, fastboot, u-boot... 214*efda1f1dSJoseph Chen * these regions are marked as M_ATTR_OVERLAP in flags. 215*efda1f1dSJoseph Chen * 216*efda1f1dSJoseph Chen * Here we check whether it overlaps with others, if 217*efda1f1dSJoseph Chen * so, set req_overlap as true. 218*efda1f1dSJoseph 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 232*efda1f1dSJoseph Chen /* 233*efda1f1dSJoseph Chen * If this request region is out size of all available 234*efda1f1dSJoseph Chen * region, ignore and return success. 235*efda1f1dSJoseph Chen */ 236305d8903SJoseph Chen if (!req_overlap) 2376e15146eSJoseph Chen return (void *)base; 2386e15146eSJoseph Chen } 239*efda1f1dSJoseph Chen 240*efda1f1dSJoseph 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); 250*efda1f1dSJoseph Chen goto out; 2516e15146eSJoseph Chen } 2526e15146eSJoseph Chen 2536e15146eSJoseph Chen if (!size) { 2546e15146eSJoseph Chen SYSMEM_E("\"%s\" size is 0 for alloc sysmem\n", name); 255*efda1f1dSJoseph 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); 261*efda1f1dSJoseph 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)) { 277*efda1f1dSJoseph 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); 282*efda1f1dSJoseph Chen goto out; 2836e15146eSJoseph Chen } else if (sysmem_is_overlap(mem->base, mem->size, base, size)) { 284*efda1f1dSJoseph Chen /* 285*efda1f1dSJoseph Chen * If this new alloc region expects overlap and the old 286*efda1f1dSJoseph Chen * region is also allowed to be overlap, just do reserve. 287*efda1f1dSJoseph 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)); 303*efda1f1dSJoseph 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); 325*efda1f1dSJoseph 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 334*efda1f1dSJoseph 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)); 347*efda1f1dSJoseph 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 351*efda1f1dSJoseph 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; 362*efda1f1dSJoseph Chen 363*efda1f1dSJoseph Chen out: 364*efda1f1dSJoseph Chen return (attr.flags & M_ATTR_PEEK) ? (void *)base : NULL; 365ffa8f8b7SJoseph Chen } 366ffa8f8b7SJoseph Chen 3676e15146eSJoseph Chen void *sysmem_alloc_base(enum memblk_id id, phys_addr_t base, phys_size_t size) 368ffa8f8b7SJoseph Chen { 3696e15146eSJoseph Chen void *paddr; 370ffa8f8b7SJoseph Chen 3716e15146eSJoseph Chen paddr = sysmem_alloc_align_base(id, 3726e15146eSJoseph Chen NULL, 373ffa8f8b7SJoseph Chen base, 374ffa8f8b7SJoseph Chen size, 375ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 3766e15146eSJoseph Chen if (!paddr) 3776e15146eSJoseph Chen sysmem_dump(); 3786e15146eSJoseph Chen 3796e15146eSJoseph Chen return paddr; 380ffa8f8b7SJoseph Chen } 381ffa8f8b7SJoseph Chen 3826e15146eSJoseph Chen void *sysmem_alloc_base_by_name(const char *name, 3836e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 384ffa8f8b7SJoseph Chen { 3856e15146eSJoseph Chen void *paddr; 3866e15146eSJoseph Chen 3876e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_BY_NAME, 3886e15146eSJoseph Chen name, 3896e15146eSJoseph Chen base, 390ffa8f8b7SJoseph Chen size, 391ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 3926e15146eSJoseph Chen if (!paddr) 3936e15146eSJoseph Chen sysmem_dump(); 3946e15146eSJoseph Chen 3956e15146eSJoseph Chen return paddr; 3966e15146eSJoseph Chen } 3976e15146eSJoseph Chen 3986e15146eSJoseph Chen void *sysmem_fdt_reserve_alloc_base(const char *name, 3996e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 4006e15146eSJoseph Chen { 4016e15146eSJoseph Chen void *paddr; 4026e15146eSJoseph Chen 4036e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_FDT_RESV, 4046e15146eSJoseph Chen name, 4056e15146eSJoseph Chen base, 4066e15146eSJoseph Chen size, 4076e15146eSJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 4086e15146eSJoseph Chen if (!paddr) 4096e15146eSJoseph Chen sysmem_dump(); 4106e15146eSJoseph Chen 4116e15146eSJoseph Chen return paddr; 412ffa8f8b7SJoseph Chen } 413ffa8f8b7SJoseph Chen 414ffa8f8b7SJoseph Chen int sysmem_free(phys_addr_t base) 415ffa8f8b7SJoseph Chen { 416ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 4176e15146eSJoseph Chen struct memblock *mem; 418ffa8f8b7SJoseph Chen struct list_head *node; 4196e15146eSJoseph Chen int ret, found = 0; 420ffa8f8b7SJoseph Chen 421ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 422ffa8f8b7SJoseph Chen return -ENOSYS; 423ffa8f8b7SJoseph Chen 424ffa8f8b7SJoseph Chen /* Find existence */ 425ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 4266e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 4276e15146eSJoseph Chen if (mem->base == base) { 428ffa8f8b7SJoseph Chen found = 1; 429ffa8f8b7SJoseph Chen break; 430ffa8f8b7SJoseph Chen } 431ffa8f8b7SJoseph Chen } 432ffa8f8b7SJoseph Chen 433ffa8f8b7SJoseph Chen if (!found) { 4346e15146eSJoseph Chen SYSMEM_E("Failed to free no allocated sysmem at 0x%08lx\n", 4356e15146eSJoseph Chen (ulong)base); 436ffa8f8b7SJoseph Chen return -EINVAL; 437ffa8f8b7SJoseph Chen } 438ffa8f8b7SJoseph Chen 4396e15146eSJoseph Chen ret = lmb_free(&sysmem->lmb, mem->base, mem->size); 440ffa8f8b7SJoseph Chen if (ret >= 0) { 4416e15146eSJoseph Chen SYSMEM_D("Free: \"%s\" 0x%08lx - 0x%08lx\n", 4426e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 4436e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 444ffa8f8b7SJoseph Chen sysmem->allocated_cnt--; 4456e15146eSJoseph Chen list_del(&mem->node); 4466e15146eSJoseph Chen free(mem); 447ffa8f8b7SJoseph Chen } else { 4486e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\" at 0x%08lx\n", 4496e15146eSJoseph Chen mem->attr.name, (ulong)base); 450ffa8f8b7SJoseph Chen } 451ffa8f8b7SJoseph Chen 452ffa8f8b7SJoseph Chen return (ret >= 0) ? 0 : ret; 453ffa8f8b7SJoseph Chen } 454ffa8f8b7SJoseph Chen 4556e15146eSJoseph Chen int sysmem_initr(void) 4566e15146eSJoseph Chen { 4576e15146eSJoseph Chen return sysmem_init(); 4586e15146eSJoseph Chen } 4596e15146eSJoseph Chen 460ffa8f8b7SJoseph Chen int sysmem_init(void) 461ffa8f8b7SJoseph Chen { 462ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 463ffa8f8b7SJoseph Chen phys_addr_t mem_start; 464ffa8f8b7SJoseph Chen phys_size_t mem_size; 465ffa8f8b7SJoseph Chen int ret; 466ffa8f8b7SJoseph Chen 467ffa8f8b7SJoseph Chen lmb_init(&sysmem->lmb); 468ffa8f8b7SJoseph Chen INIT_LIST_HEAD(&sysmem->allocated_head); 469ffa8f8b7SJoseph Chen sysmem->allocated_cnt = 0; 4706e15146eSJoseph Chen if (gd->flags & GD_FLG_RELOC) { 4716e15146eSJoseph Chen sysmem->has_initr = true; 4726e15146eSJoseph Chen } else { 4736e15146eSJoseph Chen SYSMEM_I("init\n"); 4746e15146eSJoseph Chen sysmem->has_initf = true; 4756e15146eSJoseph Chen } 476ffa8f8b7SJoseph Chen 477ffa8f8b7SJoseph Chen /* Add all available system memory */ 478ffa8f8b7SJoseph Chen #ifdef CONFIG_NR_DRAM_BANKS 479ffa8f8b7SJoseph Chen int i; 480ffa8f8b7SJoseph Chen 481ffa8f8b7SJoseph Chen for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 4826e15146eSJoseph Chen if (!gd->bd->bi_dram[i].size) 4836e15146eSJoseph Chen continue; 4846e15146eSJoseph Chen 485ffa8f8b7SJoseph Chen ret = sysmem_add(gd->bd->bi_dram[i].start, 486ffa8f8b7SJoseph Chen gd->bd->bi_dram[i].size); 487ffa8f8b7SJoseph Chen if (ret) { 488ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bi_dram[%d]\n", i); 4896e15146eSJoseph Chen goto fail; 490ffa8f8b7SJoseph Chen } 491ffa8f8b7SJoseph Chen } 492ffa8f8b7SJoseph Chen #else 493ffa8f8b7SJoseph Chen mem_start = env_get_bootm_low(); 494ffa8f8b7SJoseph Chen mem_size = env_get_bootm_size(); 495ffa8f8b7SJoseph Chen ret = sysmem_add(mem_start, mem_size); 496ffa8f8b7SJoseph Chen if (ret) { 497ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bootm_low/size\n"); 4986e15146eSJoseph Chen goto fail; 499ffa8f8b7SJoseph Chen } 500ffa8f8b7SJoseph Chen #endif 501ffa8f8b7SJoseph Chen /* Reserved for board */ 502ffa8f8b7SJoseph Chen ret = board_sysmem_reserve(sysmem); 503ffa8f8b7SJoseph Chen if (ret) { 504ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for board\n"); 5056e15146eSJoseph Chen goto fail; 506ffa8f8b7SJoseph Chen } 507ffa8f8b7SJoseph Chen 5086e15146eSJoseph Chen /* Reserved for U-boot framework: 'reserve_xxx()' */ 5096e15146eSJoseph Chen mem_start = gd->start_addr_sp; 510ffa8f8b7SJoseph Chen mem_size = gd->ram_top - mem_start; 5116e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_UBOOT, mem_start, mem_size)) { 512ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for U-Boot framework\n"); 5136e15146eSJoseph Chen ret = -ENOMEM; 5146e15146eSJoseph Chen goto fail; 515ffa8f8b7SJoseph Chen } 516ffa8f8b7SJoseph Chen 5176e15146eSJoseph Chen /* Reserved for U-Boot stack */ 5186e15146eSJoseph Chen mem_start = gd->start_addr_sp - CONFIG_SYS_STACK_SIZE; 5196e15146eSJoseph Chen mem_size = CONFIG_SYS_STACK_SIZE; 5206e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_STACK, mem_start, mem_size)) { 5216e15146eSJoseph Chen SYSMEM_E("Failed to reserve sysmem for stack\n"); 5226e15146eSJoseph Chen ret = -ENOMEM; 5236e15146eSJoseph Chen goto fail; 5246e15146eSJoseph Chen } 525ffa8f8b7SJoseph Chen 526ffa8f8b7SJoseph Chen return 0; 5276e15146eSJoseph Chen 5286e15146eSJoseph Chen fail: 5296e15146eSJoseph Chen if (ret && !(gd->flags & GD_FLG_RELOC)) { 5306e15146eSJoseph Chen sysmem_dump(); 5316e15146eSJoseph Chen SYSMEM_W("Maybe malloc size %d MiB is too large?\n\n", 5326e15146eSJoseph Chen SIZE_MB(CONFIG_SYS_MALLOC_LEN)); 5336e15146eSJoseph Chen } 5346e15146eSJoseph Chen 5356e15146eSJoseph Chen return ret; 536ffa8f8b7SJoseph Chen } 537ffa8f8b7SJoseph Chen 538ffa8f8b7SJoseph Chen __weak int board_sysmem_reserve(struct sysmem *sysmem) 539ffa8f8b7SJoseph Chen { 540ffa8f8b7SJoseph Chen /* please define platform specific board_sysmem_reserve() */ 541ffa8f8b7SJoseph Chen return 0; 542ffa8f8b7SJoseph Chen } 543ffa8f8b7SJoseph Chen 5446e15146eSJoseph Chen static int do_dump_sysmem(cmd_tbl_t *cmdtp, int flag, 5456e15146eSJoseph Chen int argc, char *const argv[]) 546ffa8f8b7SJoseph Chen { 5476e15146eSJoseph Chen sysmem_dump(); 548ffa8f8b7SJoseph Chen return 0; 549ffa8f8b7SJoseph Chen } 5506e15146eSJoseph Chen 5516e15146eSJoseph Chen U_BOOT_CMD( 5526e15146eSJoseph Chen dump_sysmem, 1, 1, do_dump_sysmem, 5536e15146eSJoseph Chen "Dump sysmem layout", 5546e15146eSJoseph Chen "" 5556e15146eSJoseph Chen ); 556