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; 1976e15146eSJoseph Chen bool req_overlap = false; 198ffa8f8b7SJoseph Chen 199ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 200ffa8f8b7SJoseph Chen return NULL; 201ffa8f8b7SJoseph Chen 2026e15146eSJoseph Chen if (id == MEMBLK_ID_BY_NAME || id == MEMBLK_ID_FDT_RESV) { 2036e15146eSJoseph Chen if (!mem_name) { 204ffa8f8b7SJoseph Chen SYSMEM_E("NULL name for alloc sysmem\n"); 205ffa8f8b7SJoseph Chen return NULL; 2066e15146eSJoseph Chen } else if (id == MEMBLK_ID_FDT_RESV) { 2076e15146eSJoseph Chen req_overlap = true; 2086e15146eSJoseph Chen if (base >= gd->ram_top) 2096e15146eSJoseph Chen return (void *)base; 2106e15146eSJoseph Chen } 2116e15146eSJoseph Chen name = sysmem_alias2name(mem_name, (int *)&id); 2126e15146eSJoseph Chen attr = mem_attr[id]; 213*a90f2861SJoseph Chen if (!attr.name) 214*a90f2861SJoseph Chen attr.name = strdup(name); 2156e15146eSJoseph Chen } else if (id > MEMBLK_ID_UNK && id < MEMBLK_ID_MAX) { 2166e15146eSJoseph Chen attr = mem_attr[id]; 2176e15146eSJoseph Chen name = attr.name; 2186e15146eSJoseph Chen } else { 2196e15146eSJoseph Chen SYSMEM_E("Unsupport memblk id %d for alloc sysmem\n", id); 2206e15146eSJoseph Chen return NULL; 2216e15146eSJoseph Chen } 2226e15146eSJoseph Chen 2236e15146eSJoseph Chen if (!size) { 2246e15146eSJoseph Chen SYSMEM_E("\"%s\" size is 0 for alloc sysmem\n", name); 2256e15146eSJoseph Chen return NULL; 226ffa8f8b7SJoseph Chen } 227ffa8f8b7SJoseph Chen 228727ebf6dSJoseph Chen if (!IS_ALIGNED(base, 4)) { 2296e15146eSJoseph Chen SYSMEM_E("\"%s\" base=0x%08lx is not 4-byte aligned\n", 2306e15146eSJoseph Chen name, (ulong)base); 231727ebf6dSJoseph Chen return NULL; 232727ebf6dSJoseph Chen } 233727ebf6dSJoseph Chen 234727ebf6dSJoseph Chen /* Must be 4-byte aligned */ 235727ebf6dSJoseph Chen size = ALIGN(size, 4); 236727ebf6dSJoseph Chen 2376e15146eSJoseph Chen SYSMEM_D("Enter alloc: \"%s\" 0x%08lx - 0x%08lx\n", 2386e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size)); 2396e15146eSJoseph Chen 240ffa8f8b7SJoseph Chen /* Already allocated ? */ 241ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 2426e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 2436e15146eSJoseph Chen SYSMEM_D("Has allcated: %s, 0x%08lx - 0x%08lx\n", 2446e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 2456e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 2466e15146eSJoseph Chen if (!strcmp(mem->attr.name, name)) { 247ffa8f8b7SJoseph Chen SYSMEM_E("Failed to double alloc for existence \"%s\"\n", name); 248ffa8f8b7SJoseph Chen return NULL; 2496e15146eSJoseph Chen } else if (sysmem_is_overlap(mem->base, mem->size, base, size)) { 2506e15146eSJoseph Chen if (req_overlap && mem->attr.flags & M_ATTR_OVERLAP) { 2516e15146eSJoseph Chen if (lmb_reserve(&sysmem->lmb, base, size)) 2526e15146eSJoseph Chen SYSMEM_E("Failed to overlap alloc \"%s\" " 2536e15146eSJoseph Chen "at 0x%08lx - 0x%08lx\n", 2546e15146eSJoseph Chen name, (ulong)base, 2556e15146eSJoseph Chen (ulong)(base + size)); 2566e15146eSJoseph Chen return (void *)base; 2576e15146eSJoseph Chen } 2586e15146eSJoseph Chen 2596e15146eSJoseph Chen SYSMEM_E("\"%s\" (0x%08lx - 0x%08lx) alloc is " 2606e15146eSJoseph Chen "overlap with existence \"%s\" (0x%08lx - " 2616e15146eSJoseph Chen "0x%08lx)\n", 2626e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size), 2636e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 2646e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 265ffa8f8b7SJoseph Chen return NULL; 266ffa8f8b7SJoseph Chen } 267ffa8f8b7SJoseph Chen } 268ffa8f8b7SJoseph Chen 2696e15146eSJoseph Chen /* Add overflow check magic ? */ 2706e15146eSJoseph Chen if (attr.flags & M_ATTR_OFC) 271ffa8f8b7SJoseph Chen alloc_size = size + sizeof(*check); 2726e15146eSJoseph Chen else 2736e15146eSJoseph Chen alloc_size = size; 2746e15146eSJoseph Chen 2756e15146eSJoseph Chen /* Alloc anywhere ? */ 276ffa8f8b7SJoseph Chen if (base == SYSMEM_ALLOC_ANYWHERE) 277ffa8f8b7SJoseph Chen alloc_base = base; 278ffa8f8b7SJoseph Chen else 279ffa8f8b7SJoseph Chen alloc_base = base + alloc_size; /* LMB is align down alloc mechanism */ 280ffa8f8b7SJoseph Chen 281ffa8f8b7SJoseph Chen paddr = lmb_alloc_base(&sysmem->lmb, alloc_size, align, alloc_base); 282ffa8f8b7SJoseph Chen if (paddr) { 283ffa8f8b7SJoseph Chen if ((paddr == base) || (base == SYSMEM_ALLOC_ANYWHERE)) { 2846e15146eSJoseph Chen mem = malloc(sizeof(*mem)); 2856e15146eSJoseph Chen if (!mem) { 286ffa8f8b7SJoseph Chen SYSMEM_E("No memory for \"%s\" alloc sysmem\n", name); 287ffa8f8b7SJoseph Chen return NULL; 288ffa8f8b7SJoseph Chen } 289ffa8f8b7SJoseph Chen 2906e15146eSJoseph Chen mem->base = paddr; 2916e15146eSJoseph Chen mem->size = alloc_size; 2926e15146eSJoseph Chen mem->attr = attr; 293ffa8f8b7SJoseph Chen sysmem->allocated_cnt++; 2946e15146eSJoseph Chen list_add_tail(&mem->node, &sysmem->allocated_head); 295ffa8f8b7SJoseph Chen 2966e15146eSJoseph Chen if (mem->attr.flags & M_ATTR_OFC) { 2976e15146eSJoseph Chen check = (struct memcheck *)(paddr + size); 298ffa8f8b7SJoseph Chen check->magic = SYSMEM_MAGIC; 2996e15146eSJoseph Chen } else if (mem->attr.flags & M_ATTR_HOFC) { 3006e15146eSJoseph Chen check = (struct memcheck *)(paddr - sizeof(*check)); 3016e15146eSJoseph Chen check->magic = SYSMEM_MAGIC; 3026e15146eSJoseph Chen } 303ffa8f8b7SJoseph Chen } else { 3046e15146eSJoseph Chen SYSMEM_E("Failed to alloc \"%s\" expect at 0x%08lx - 0x%08lx " 3056e15146eSJoseph Chen "but at 0x%08lx - x%08lx\n", 3066e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size), 3076e15146eSJoseph Chen (ulong)paddr, (ulong)(paddr + size)); 3086e15146eSJoseph Chen if (lmb_free(&sysmem->lmb, paddr, alloc_size)) 3096e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\"\n", name); 3106e15146eSJoseph Chen 311ffa8f8b7SJoseph Chen return NULL; 312ffa8f8b7SJoseph Chen } 313ffa8f8b7SJoseph Chen } else { 3146e15146eSJoseph Chen SYSMEM_E("Failed to alloc \"%s\" at 0x%08lx - 0x%08lx\n", 3156e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size)); 316ffa8f8b7SJoseph Chen } 317ffa8f8b7SJoseph Chen 3186e15146eSJoseph Chen SYSMEM_D("Exit alloc: \"%s\", paddr=0x%08lx, size=0x%08lx, align=0x%x, anywhere=%d\n", 319ffa8f8b7SJoseph Chen name, (ulong)paddr, (ulong)size, (u32)align, !base); 320ffa8f8b7SJoseph Chen 321ffa8f8b7SJoseph Chen return (void *)paddr; 322ffa8f8b7SJoseph Chen } 323ffa8f8b7SJoseph Chen 3246e15146eSJoseph Chen void *sysmem_alloc_base(enum memblk_id id, phys_addr_t base, phys_size_t size) 325ffa8f8b7SJoseph Chen { 3266e15146eSJoseph Chen void *paddr; 327ffa8f8b7SJoseph Chen 3286e15146eSJoseph Chen paddr = sysmem_alloc_align_base(id, 3296e15146eSJoseph Chen NULL, 330ffa8f8b7SJoseph Chen base, 331ffa8f8b7SJoseph Chen size, 332ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 3336e15146eSJoseph Chen if (!paddr) 3346e15146eSJoseph Chen sysmem_dump(); 3356e15146eSJoseph Chen 3366e15146eSJoseph Chen return paddr; 337ffa8f8b7SJoseph Chen } 338ffa8f8b7SJoseph Chen 3396e15146eSJoseph Chen void *sysmem_alloc_base_by_name(const char *name, 3406e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 341ffa8f8b7SJoseph Chen { 3426e15146eSJoseph Chen void *paddr; 3436e15146eSJoseph Chen 3446e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_BY_NAME, 3456e15146eSJoseph Chen name, 3466e15146eSJoseph Chen base, 347ffa8f8b7SJoseph Chen size, 348ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 3496e15146eSJoseph Chen if (!paddr) 3506e15146eSJoseph Chen sysmem_dump(); 3516e15146eSJoseph Chen 3526e15146eSJoseph Chen return paddr; 3536e15146eSJoseph Chen } 3546e15146eSJoseph Chen 3556e15146eSJoseph Chen void *sysmem_fdt_reserve_alloc_base(const char *name, 3566e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 3576e15146eSJoseph Chen { 3586e15146eSJoseph Chen void *paddr; 3596e15146eSJoseph Chen 3606e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_FDT_RESV, 3616e15146eSJoseph Chen name, 3626e15146eSJoseph Chen base, 3636e15146eSJoseph Chen size, 3646e15146eSJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 3656e15146eSJoseph Chen if (!paddr) 3666e15146eSJoseph Chen sysmem_dump(); 3676e15146eSJoseph Chen 3686e15146eSJoseph Chen return paddr; 369ffa8f8b7SJoseph Chen } 370ffa8f8b7SJoseph Chen 371ffa8f8b7SJoseph Chen int sysmem_free(phys_addr_t base) 372ffa8f8b7SJoseph Chen { 373ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 3746e15146eSJoseph Chen struct memblock *mem; 375ffa8f8b7SJoseph Chen struct list_head *node; 3766e15146eSJoseph Chen int ret, found = 0; 377ffa8f8b7SJoseph Chen 378ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 379ffa8f8b7SJoseph Chen return -ENOSYS; 380ffa8f8b7SJoseph Chen 381ffa8f8b7SJoseph Chen /* Find existence */ 382ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 3836e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 3846e15146eSJoseph Chen if (mem->base == base) { 385ffa8f8b7SJoseph Chen found = 1; 386ffa8f8b7SJoseph Chen break; 387ffa8f8b7SJoseph Chen } 388ffa8f8b7SJoseph Chen } 389ffa8f8b7SJoseph Chen 390ffa8f8b7SJoseph Chen if (!found) { 3916e15146eSJoseph Chen SYSMEM_E("Failed to free no allocated sysmem at 0x%08lx\n", 3926e15146eSJoseph Chen (ulong)base); 393ffa8f8b7SJoseph Chen return -EINVAL; 394ffa8f8b7SJoseph Chen } 395ffa8f8b7SJoseph Chen 3966e15146eSJoseph Chen ret = lmb_free(&sysmem->lmb, mem->base, mem->size); 397ffa8f8b7SJoseph Chen if (ret >= 0) { 3986e15146eSJoseph Chen SYSMEM_D("Free: \"%s\" 0x%08lx - 0x%08lx\n", 3996e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 4006e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 401ffa8f8b7SJoseph Chen sysmem->allocated_cnt--; 4026e15146eSJoseph Chen list_del(&mem->node); 4036e15146eSJoseph Chen free(mem); 404ffa8f8b7SJoseph Chen } else { 4056e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\" at 0x%08lx\n", 4066e15146eSJoseph Chen mem->attr.name, (ulong)base); 407ffa8f8b7SJoseph Chen } 408ffa8f8b7SJoseph Chen 409ffa8f8b7SJoseph Chen return (ret >= 0) ? 0 : ret; 410ffa8f8b7SJoseph Chen } 411ffa8f8b7SJoseph Chen 4126e15146eSJoseph Chen int sysmem_initr(void) 4136e15146eSJoseph Chen { 4146e15146eSJoseph Chen return sysmem_init(); 4156e15146eSJoseph Chen } 4166e15146eSJoseph Chen 417ffa8f8b7SJoseph Chen int sysmem_init(void) 418ffa8f8b7SJoseph Chen { 419ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 420ffa8f8b7SJoseph Chen phys_addr_t mem_start; 421ffa8f8b7SJoseph Chen phys_size_t mem_size; 422ffa8f8b7SJoseph Chen int ret; 423ffa8f8b7SJoseph Chen 424ffa8f8b7SJoseph Chen lmb_init(&sysmem->lmb); 425ffa8f8b7SJoseph Chen INIT_LIST_HEAD(&sysmem->allocated_head); 426ffa8f8b7SJoseph Chen sysmem->allocated_cnt = 0; 4276e15146eSJoseph Chen if (gd->flags & GD_FLG_RELOC) { 4286e15146eSJoseph Chen sysmem->has_initr = true; 4296e15146eSJoseph Chen } else { 4306e15146eSJoseph Chen SYSMEM_I("init\n"); 4316e15146eSJoseph Chen sysmem->has_initf = true; 4326e15146eSJoseph Chen } 433ffa8f8b7SJoseph Chen 434ffa8f8b7SJoseph Chen /* Add all available system memory */ 435ffa8f8b7SJoseph Chen #ifdef CONFIG_NR_DRAM_BANKS 436ffa8f8b7SJoseph Chen int i; 437ffa8f8b7SJoseph Chen 438ffa8f8b7SJoseph Chen for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 4396e15146eSJoseph Chen if (!gd->bd->bi_dram[i].size) 4406e15146eSJoseph Chen continue; 4416e15146eSJoseph Chen 442ffa8f8b7SJoseph Chen ret = sysmem_add(gd->bd->bi_dram[i].start, 443ffa8f8b7SJoseph Chen gd->bd->bi_dram[i].size); 444ffa8f8b7SJoseph Chen if (ret) { 445ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bi_dram[%d]\n", i); 4466e15146eSJoseph Chen goto fail; 447ffa8f8b7SJoseph Chen } 448ffa8f8b7SJoseph Chen } 449ffa8f8b7SJoseph Chen #else 450ffa8f8b7SJoseph Chen mem_start = env_get_bootm_low(); 451ffa8f8b7SJoseph Chen mem_size = env_get_bootm_size(); 452ffa8f8b7SJoseph Chen ret = sysmem_add(mem_start, mem_size); 453ffa8f8b7SJoseph Chen if (ret) { 454ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bootm_low/size\n"); 4556e15146eSJoseph Chen goto fail; 456ffa8f8b7SJoseph Chen } 457ffa8f8b7SJoseph Chen #endif 458ffa8f8b7SJoseph Chen /* Reserved for board */ 459ffa8f8b7SJoseph Chen ret = board_sysmem_reserve(sysmem); 460ffa8f8b7SJoseph Chen if (ret) { 461ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for board\n"); 4626e15146eSJoseph Chen goto fail; 463ffa8f8b7SJoseph Chen } 464ffa8f8b7SJoseph Chen 4656e15146eSJoseph Chen /* Reserved for U-boot framework: 'reserve_xxx()' */ 4666e15146eSJoseph Chen mem_start = gd->start_addr_sp; 467ffa8f8b7SJoseph Chen mem_size = gd->ram_top - mem_start; 4686e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_UBOOT, mem_start, mem_size)) { 469ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for U-Boot framework\n"); 4706e15146eSJoseph Chen ret = -ENOMEM; 4716e15146eSJoseph Chen goto fail; 472ffa8f8b7SJoseph Chen } 473ffa8f8b7SJoseph Chen 4746e15146eSJoseph Chen /* Reserved for U-Boot stack */ 4756e15146eSJoseph Chen mem_start = gd->start_addr_sp - CONFIG_SYS_STACK_SIZE; 4766e15146eSJoseph Chen mem_size = CONFIG_SYS_STACK_SIZE; 4776e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_STACK, mem_start, mem_size)) { 4786e15146eSJoseph Chen SYSMEM_E("Failed to reserve sysmem for stack\n"); 4796e15146eSJoseph Chen ret = -ENOMEM; 4806e15146eSJoseph Chen goto fail; 4816e15146eSJoseph Chen } 482ffa8f8b7SJoseph Chen 483ffa8f8b7SJoseph Chen return 0; 4846e15146eSJoseph Chen 4856e15146eSJoseph Chen fail: 4866e15146eSJoseph Chen if (ret && !(gd->flags & GD_FLG_RELOC)) { 4876e15146eSJoseph Chen sysmem_dump(); 4886e15146eSJoseph Chen SYSMEM_W("Maybe malloc size %d MiB is too large?\n\n", 4896e15146eSJoseph Chen SIZE_MB(CONFIG_SYS_MALLOC_LEN)); 4906e15146eSJoseph Chen } 4916e15146eSJoseph Chen 4926e15146eSJoseph Chen return ret; 493ffa8f8b7SJoseph Chen } 494ffa8f8b7SJoseph Chen 495ffa8f8b7SJoseph Chen __weak int board_sysmem_reserve(struct sysmem *sysmem) 496ffa8f8b7SJoseph Chen { 497ffa8f8b7SJoseph Chen /* please define platform specific board_sysmem_reserve() */ 498ffa8f8b7SJoseph Chen return 0; 499ffa8f8b7SJoseph Chen } 500ffa8f8b7SJoseph Chen 5016e15146eSJoseph Chen static int do_dump_sysmem(cmd_tbl_t *cmdtp, int flag, 5026e15146eSJoseph Chen int argc, char *const argv[]) 503ffa8f8b7SJoseph Chen { 5046e15146eSJoseph Chen sysmem_dump(); 505ffa8f8b7SJoseph Chen return 0; 506ffa8f8b7SJoseph Chen } 5076e15146eSJoseph Chen 5086e15146eSJoseph Chen U_BOOT_CMD( 5096e15146eSJoseph Chen dump_sysmem, 1, 1, do_dump_sysmem, 5106e15146eSJoseph Chen "Dump sysmem layout", 5116e15146eSJoseph Chen "" 5126e15146eSJoseph Chen ); 513