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 23*6e15146eSJoseph Chen struct memcheck { 24ffa8f8b7SJoseph Chen uint32_t magic; 25ffa8f8b7SJoseph Chen }; 26ffa8f8b7SJoseph Chen 27*6e15146eSJoseph Chen /* Global for platform, must in data section */ 28*6e15146eSJoseph Chen struct sysmem plat_sysmem __section(".data") = { 29*6e15146eSJoseph Chen .has_initf = false, 30*6e15146eSJoseph Chen .has_initr = false, 31*6e15146eSJoseph Chen }; 32ffa8f8b7SJoseph Chen 33*6e15146eSJoseph Chen bool sysmem_has_init(void) 34*6e15146eSJoseph Chen { 35*6e15146eSJoseph Chen return gd->flags & GD_FLG_RELOC ? 36*6e15146eSJoseph 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; 43*6e15146eSJoseph Chen struct memblock *mem; 44*6e15146eSJoseph 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; 49*6e15146eSJoseph 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 */ 58*6e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n"); 59ffa8f8b7SJoseph Chen for (i = 0; i < lmb->memory.cnt; i++) { 60ffa8f8b7SJoseph Chen memory_size += lmb->memory.region[i].size; 61*6e15146eSJoseph Chen printf(" memory.rgn[%ld].addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", i, 62*6e15146eSJoseph Chen (ulong)lmb->memory.region[i].base, 63*6e15146eSJoseph Chen (ulong)lmb->memory.region[i].base + 64*6e15146eSJoseph 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; 74*6e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n"); 75ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 76*6e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 77*6e15146eSJoseph Chen allocated_size += mem->size; 78*6e15146eSJoseph Chen if (mem->attr.flags & M_ATTR_OFC) { 79*6e15146eSJoseph Chen check = (struct memcheck *) 80*6e15146eSJoseph Chen (mem->base + mem->size - sizeof(*check)); 81*6e15146eSJoseph Chen overflow = (check->magic != SYSMEM_MAGIC); 82*6e15146eSJoseph Chen } else if (mem->attr.flags & M_ATTR_HOFC) { 83*6e15146eSJoseph Chen check = (struct memcheck *) 84*6e15146eSJoseph Chen (mem->base - sizeof(*check)); 85*6e15146eSJoseph Chen overflow = (check->magic != SYSMEM_MAGIC); 86*6e15146eSJoseph Chen } else { 87*6e15146eSJoseph Chen overflow = false; 88*6e15146eSJoseph Chen } 89*6e15146eSJoseph Chen 90ffa8f8b7SJoseph Chen printf(" allocated.rgn[%ld].name = \"%s\" %s\n", 91*6e15146eSJoseph Chen i, mem->attr.name, overflow ? " <Overflow!>" : ""); 92*6e15146eSJoseph Chen printf(" .addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", 93*6e15146eSJoseph Chen (ulong)mem->base, (ulong)(mem->base + mem->size), 94*6e15146eSJoseph Chen (ulong)mem->size); 95ffa8f8b7SJoseph Chen i++; 96ffa8f8b7SJoseph Chen } 97*6e15146eSJoseph Chen 98*6e15146eSJoseph Chen printf("\n malloc_r: %d MiB, malloc_f: %d KiB\n", 99*6e15146eSJoseph 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 */ 106*6e15146eSJoseph 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; 110*6e15146eSJoseph Chen printf(" LMB.reserved[%ld].addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", i, 111*6e15146eSJoseph Chen (ulong)lmb->reserved.region[i].base, 112*6e15146eSJoseph Chen (ulong)lmb->reserved.region[i].base + 113*6e15146eSJoseph 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)); 121*6e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n\n"); 122ffa8f8b7SJoseph Chen } 123ffa8f8b7SJoseph Chen 124*6e15146eSJoseph 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 130*6e15146eSJoseph 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 135*6e15146eSJoseph Chen if (!size) 136*6e15146eSJoseph Chen return -EINVAL; 137ffa8f8b7SJoseph Chen 138ffa8f8b7SJoseph Chen ret = lmb_add(&sysmem->lmb, base, size); 139ffa8f8b7SJoseph Chen if (ret < 0) 140*6e15146eSJoseph 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 146*6e15146eSJoseph Chen static const char *sysmem_alias2name(const char *name, int *id) 147ffa8f8b7SJoseph Chen { 148*6e15146eSJoseph Chen const char *alias; 149*6e15146eSJoseph Chen int n, i, j; 150*6e15146eSJoseph Chen int match = 0; 151ffa8f8b7SJoseph Chen 152*6e15146eSJoseph Chen for (i = 0; i < MEMBLK_ID_MAX; i++) { 153*6e15146eSJoseph Chen /* Pirmary name */ 154*6e15146eSJoseph Chen if (mem_attr[i].name && !strcasecmp(mem_attr[i].name, name)) { 155*6e15146eSJoseph Chen match = 1; 156*6e15146eSJoseph Chen goto finish; 157ffa8f8b7SJoseph Chen } 158ffa8f8b7SJoseph Chen 159*6e15146eSJoseph Chen /* Alias name */ 160*6e15146eSJoseph Chen alias = mem_attr[i].alias[0]; 161*6e15146eSJoseph Chen if (!alias) 162*6e15146eSJoseph Chen continue; 163*6e15146eSJoseph Chen 164*6e15146eSJoseph Chen n = ARRAY_SIZE(mem_attr[i].alias); 165*6e15146eSJoseph Chen for (j = 0; j < n; j++, alias++) { 166*6e15146eSJoseph Chen if (alias && !strcasecmp(alias, name)) { 167*6e15146eSJoseph Chen match = 1; 168*6e15146eSJoseph Chen goto finish; 169*6e15146eSJoseph Chen } 170ffa8f8b7SJoseph Chen } 171ffa8f8b7SJoseph Chen } 172ffa8f8b7SJoseph Chen 173*6e15146eSJoseph Chen finish: 174*6e15146eSJoseph Chen if (match) { 175*6e15146eSJoseph Chen *id = i; 176*6e15146eSJoseph Chen return mem_attr[i].name; 177ffa8f8b7SJoseph Chen } 178ffa8f8b7SJoseph Chen 179*6e15146eSJoseph Chen return name; 180ffa8f8b7SJoseph Chen } 181ffa8f8b7SJoseph Chen 182*6e15146eSJoseph Chen static void *sysmem_alloc_align_base(enum memblk_id id, 183*6e15146eSJoseph 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; 189*6e15146eSJoseph Chen struct memblk_attr attr; 190*6e15146eSJoseph Chen struct memblock *mem; 191*6e15146eSJoseph Chen struct memcheck *check; 192ffa8f8b7SJoseph Chen struct list_head *node; 193*6e15146eSJoseph Chen const char *name; 194ffa8f8b7SJoseph Chen phys_addr_t paddr; 195ffa8f8b7SJoseph Chen phys_addr_t alloc_base; 196ffa8f8b7SJoseph Chen phys_size_t alloc_size; 197*6e15146eSJoseph Chen bool req_overlap = false; 198ffa8f8b7SJoseph Chen 199ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 200ffa8f8b7SJoseph Chen return NULL; 201ffa8f8b7SJoseph Chen 202*6e15146eSJoseph Chen if (id == MEMBLK_ID_BY_NAME || id == MEMBLK_ID_FDT_RESV) { 203*6e15146eSJoseph Chen if (!mem_name) { 204ffa8f8b7SJoseph Chen SYSMEM_E("NULL name for alloc sysmem\n"); 205ffa8f8b7SJoseph Chen return NULL; 206*6e15146eSJoseph Chen } else if (id == MEMBLK_ID_FDT_RESV) { 207*6e15146eSJoseph Chen req_overlap = true; 208*6e15146eSJoseph Chen if (base >= gd->ram_top) 209*6e15146eSJoseph Chen return (void *)base; 210*6e15146eSJoseph Chen } 211*6e15146eSJoseph Chen name = sysmem_alias2name(mem_name, (int *)&id); 212*6e15146eSJoseph Chen attr = mem_attr[id]; 213*6e15146eSJoseph Chen } else if (id > MEMBLK_ID_UNK && id < MEMBLK_ID_MAX) { 214*6e15146eSJoseph Chen attr = mem_attr[id]; 215*6e15146eSJoseph Chen name = attr.name; 216*6e15146eSJoseph Chen } else { 217*6e15146eSJoseph Chen SYSMEM_E("Unsupport memblk id %d for alloc sysmem\n", id); 218*6e15146eSJoseph Chen return NULL; 219*6e15146eSJoseph Chen } 220*6e15146eSJoseph Chen 221*6e15146eSJoseph Chen if (!size) { 222*6e15146eSJoseph Chen SYSMEM_E("\"%s\" size is 0 for alloc sysmem\n", name); 223*6e15146eSJoseph Chen return NULL; 224ffa8f8b7SJoseph Chen } 225ffa8f8b7SJoseph Chen 226727ebf6dSJoseph Chen if (!IS_ALIGNED(base, 4)) { 227*6e15146eSJoseph Chen SYSMEM_E("\"%s\" base=0x%08lx is not 4-byte aligned\n", 228*6e15146eSJoseph Chen name, (ulong)base); 229727ebf6dSJoseph Chen return NULL; 230727ebf6dSJoseph Chen } 231727ebf6dSJoseph Chen 232727ebf6dSJoseph Chen /* Must be 4-byte aligned */ 233727ebf6dSJoseph Chen size = ALIGN(size, 4); 234727ebf6dSJoseph Chen 235*6e15146eSJoseph Chen SYSMEM_D("Enter alloc: \"%s\" 0x%08lx - 0x%08lx\n", 236*6e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size)); 237*6e15146eSJoseph Chen 238ffa8f8b7SJoseph Chen /* Already allocated ? */ 239ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 240*6e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 241*6e15146eSJoseph Chen SYSMEM_D("Has allcated: %s, 0x%08lx - 0x%08lx\n", 242*6e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 243*6e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 244*6e15146eSJoseph Chen if (!strcmp(mem->attr.name, name)) { 245ffa8f8b7SJoseph Chen SYSMEM_E("Failed to double alloc for existence \"%s\"\n", name); 246ffa8f8b7SJoseph Chen return NULL; 247*6e15146eSJoseph Chen } else if (sysmem_is_overlap(mem->base, mem->size, base, size)) { 248*6e15146eSJoseph Chen if (req_overlap && mem->attr.flags & M_ATTR_OVERLAP) { 249*6e15146eSJoseph Chen if (lmb_reserve(&sysmem->lmb, base, size)) 250*6e15146eSJoseph Chen SYSMEM_E("Failed to overlap alloc \"%s\" " 251*6e15146eSJoseph Chen "at 0x%08lx - 0x%08lx\n", 252*6e15146eSJoseph Chen name, (ulong)base, 253*6e15146eSJoseph Chen (ulong)(base + size)); 254*6e15146eSJoseph Chen return (void *)base; 255*6e15146eSJoseph Chen } 256*6e15146eSJoseph Chen 257*6e15146eSJoseph Chen SYSMEM_E("\"%s\" (0x%08lx - 0x%08lx) alloc is " 258*6e15146eSJoseph Chen "overlap with existence \"%s\" (0x%08lx - " 259*6e15146eSJoseph Chen "0x%08lx)\n", 260*6e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size), 261*6e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 262*6e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 263ffa8f8b7SJoseph Chen return NULL; 264ffa8f8b7SJoseph Chen } 265ffa8f8b7SJoseph Chen } 266ffa8f8b7SJoseph Chen 267*6e15146eSJoseph Chen /* Add overflow check magic ? */ 268*6e15146eSJoseph Chen if (attr.flags & M_ATTR_OFC) 269ffa8f8b7SJoseph Chen alloc_size = size + sizeof(*check); 270*6e15146eSJoseph Chen else 271*6e15146eSJoseph Chen alloc_size = size; 272*6e15146eSJoseph Chen 273*6e15146eSJoseph Chen /* Alloc anywhere ? */ 274ffa8f8b7SJoseph Chen if (base == SYSMEM_ALLOC_ANYWHERE) 275ffa8f8b7SJoseph Chen alloc_base = base; 276ffa8f8b7SJoseph Chen else 277ffa8f8b7SJoseph Chen alloc_base = base + alloc_size; /* LMB is align down alloc mechanism */ 278ffa8f8b7SJoseph Chen 279ffa8f8b7SJoseph Chen paddr = lmb_alloc_base(&sysmem->lmb, alloc_size, align, alloc_base); 280ffa8f8b7SJoseph Chen if (paddr) { 281ffa8f8b7SJoseph Chen if ((paddr == base) || (base == SYSMEM_ALLOC_ANYWHERE)) { 282*6e15146eSJoseph Chen mem = malloc(sizeof(*mem)); 283*6e15146eSJoseph Chen if (!mem) { 284ffa8f8b7SJoseph Chen SYSMEM_E("No memory for \"%s\" alloc sysmem\n", name); 285ffa8f8b7SJoseph Chen return NULL; 286ffa8f8b7SJoseph Chen } 287ffa8f8b7SJoseph Chen 288*6e15146eSJoseph Chen mem->base = paddr; 289*6e15146eSJoseph Chen mem->size = alloc_size; 290*6e15146eSJoseph Chen mem->attr = attr; 291ffa8f8b7SJoseph Chen sysmem->allocated_cnt++; 292*6e15146eSJoseph Chen list_add_tail(&mem->node, &sysmem->allocated_head); 293ffa8f8b7SJoseph Chen 294*6e15146eSJoseph Chen if (mem->attr.flags & M_ATTR_OFC) { 295*6e15146eSJoseph Chen check = (struct memcheck *)(paddr + size); 296ffa8f8b7SJoseph Chen check->magic = SYSMEM_MAGIC; 297*6e15146eSJoseph Chen } else if (mem->attr.flags & M_ATTR_HOFC) { 298*6e15146eSJoseph Chen check = (struct memcheck *)(paddr - sizeof(*check)); 299*6e15146eSJoseph Chen check->magic = SYSMEM_MAGIC; 300*6e15146eSJoseph Chen } 301ffa8f8b7SJoseph Chen } else { 302*6e15146eSJoseph Chen SYSMEM_E("Failed to alloc \"%s\" expect at 0x%08lx - 0x%08lx " 303*6e15146eSJoseph Chen "but at 0x%08lx - x%08lx\n", 304*6e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size), 305*6e15146eSJoseph Chen (ulong)paddr, (ulong)(paddr + size)); 306*6e15146eSJoseph Chen if (lmb_free(&sysmem->lmb, paddr, alloc_size)) 307*6e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\"\n", name); 308*6e15146eSJoseph Chen 309ffa8f8b7SJoseph Chen return NULL; 310ffa8f8b7SJoseph Chen } 311ffa8f8b7SJoseph Chen } else { 312*6e15146eSJoseph Chen SYSMEM_E("Failed to alloc \"%s\" at 0x%08lx - 0x%08lx\n", 313*6e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size)); 314ffa8f8b7SJoseph Chen } 315ffa8f8b7SJoseph Chen 316*6e15146eSJoseph Chen SYSMEM_D("Exit alloc: \"%s\", paddr=0x%08lx, size=0x%08lx, align=0x%x, anywhere=%d\n", 317ffa8f8b7SJoseph Chen name, (ulong)paddr, (ulong)size, (u32)align, !base); 318ffa8f8b7SJoseph Chen 319ffa8f8b7SJoseph Chen return (void *)paddr; 320ffa8f8b7SJoseph Chen } 321ffa8f8b7SJoseph Chen 322*6e15146eSJoseph Chen void *sysmem_alloc_base(enum memblk_id id, phys_addr_t base, phys_size_t size) 323ffa8f8b7SJoseph Chen { 324*6e15146eSJoseph Chen void *paddr; 325ffa8f8b7SJoseph Chen 326*6e15146eSJoseph Chen paddr = sysmem_alloc_align_base(id, 327*6e15146eSJoseph Chen NULL, 328ffa8f8b7SJoseph Chen base, 329ffa8f8b7SJoseph Chen size, 330ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 331*6e15146eSJoseph Chen if (!paddr) 332*6e15146eSJoseph Chen sysmem_dump(); 333*6e15146eSJoseph Chen 334*6e15146eSJoseph Chen return paddr; 335ffa8f8b7SJoseph Chen } 336ffa8f8b7SJoseph Chen 337*6e15146eSJoseph Chen void *sysmem_alloc_base_by_name(const char *name, 338*6e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 339ffa8f8b7SJoseph Chen { 340*6e15146eSJoseph Chen void *paddr; 341*6e15146eSJoseph Chen 342*6e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_BY_NAME, 343*6e15146eSJoseph Chen name, 344*6e15146eSJoseph Chen base, 345ffa8f8b7SJoseph Chen size, 346ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 347*6e15146eSJoseph Chen if (!paddr) 348*6e15146eSJoseph Chen sysmem_dump(); 349*6e15146eSJoseph Chen 350*6e15146eSJoseph Chen return paddr; 351*6e15146eSJoseph Chen } 352*6e15146eSJoseph Chen 353*6e15146eSJoseph Chen void *sysmem_fdt_reserve_alloc_base(const char *name, 354*6e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 355*6e15146eSJoseph Chen { 356*6e15146eSJoseph Chen void *paddr; 357*6e15146eSJoseph Chen 358*6e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_FDT_RESV, 359*6e15146eSJoseph Chen name, 360*6e15146eSJoseph Chen base, 361*6e15146eSJoseph Chen size, 362*6e15146eSJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 363*6e15146eSJoseph Chen if (!paddr) 364*6e15146eSJoseph Chen sysmem_dump(); 365*6e15146eSJoseph Chen 366*6e15146eSJoseph Chen return paddr; 367ffa8f8b7SJoseph Chen } 368ffa8f8b7SJoseph Chen 369ffa8f8b7SJoseph Chen int sysmem_free(phys_addr_t base) 370ffa8f8b7SJoseph Chen { 371ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 372*6e15146eSJoseph Chen struct memblock *mem; 373ffa8f8b7SJoseph Chen struct list_head *node; 374*6e15146eSJoseph Chen int ret, found = 0; 375ffa8f8b7SJoseph Chen 376ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 377ffa8f8b7SJoseph Chen return -ENOSYS; 378ffa8f8b7SJoseph Chen 379ffa8f8b7SJoseph Chen /* Find existence */ 380ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 381*6e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 382*6e15146eSJoseph Chen if (mem->base == base) { 383ffa8f8b7SJoseph Chen found = 1; 384ffa8f8b7SJoseph Chen break; 385ffa8f8b7SJoseph Chen } 386ffa8f8b7SJoseph Chen } 387ffa8f8b7SJoseph Chen 388ffa8f8b7SJoseph Chen if (!found) { 389*6e15146eSJoseph Chen SYSMEM_E("Failed to free no allocated sysmem at 0x%08lx\n", 390*6e15146eSJoseph Chen (ulong)base); 391ffa8f8b7SJoseph Chen return -EINVAL; 392ffa8f8b7SJoseph Chen } 393ffa8f8b7SJoseph Chen 394*6e15146eSJoseph Chen ret = lmb_free(&sysmem->lmb, mem->base, mem->size); 395ffa8f8b7SJoseph Chen if (ret >= 0) { 396*6e15146eSJoseph Chen SYSMEM_D("Free: \"%s\" 0x%08lx - 0x%08lx\n", 397*6e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 398*6e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 399ffa8f8b7SJoseph Chen sysmem->allocated_cnt--; 400*6e15146eSJoseph Chen list_del(&mem->node); 401*6e15146eSJoseph Chen free(mem); 402ffa8f8b7SJoseph Chen } else { 403*6e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\" at 0x%08lx\n", 404*6e15146eSJoseph Chen mem->attr.name, (ulong)base); 405ffa8f8b7SJoseph Chen } 406ffa8f8b7SJoseph Chen 407ffa8f8b7SJoseph Chen return (ret >= 0) ? 0 : ret; 408ffa8f8b7SJoseph Chen } 409ffa8f8b7SJoseph Chen 410*6e15146eSJoseph Chen int sysmem_initr(void) 411*6e15146eSJoseph Chen { 412*6e15146eSJoseph Chen return sysmem_init(); 413*6e15146eSJoseph Chen } 414*6e15146eSJoseph Chen 415ffa8f8b7SJoseph Chen int sysmem_init(void) 416ffa8f8b7SJoseph Chen { 417ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 418ffa8f8b7SJoseph Chen phys_addr_t mem_start; 419ffa8f8b7SJoseph Chen phys_size_t mem_size; 420ffa8f8b7SJoseph Chen int ret; 421ffa8f8b7SJoseph Chen 422ffa8f8b7SJoseph Chen lmb_init(&sysmem->lmb); 423ffa8f8b7SJoseph Chen INIT_LIST_HEAD(&sysmem->allocated_head); 424ffa8f8b7SJoseph Chen sysmem->allocated_cnt = 0; 425*6e15146eSJoseph Chen if (gd->flags & GD_FLG_RELOC) { 426*6e15146eSJoseph Chen sysmem->has_initr = true; 427*6e15146eSJoseph Chen } else { 428*6e15146eSJoseph Chen SYSMEM_I("init\n"); 429*6e15146eSJoseph Chen sysmem->has_initf = true; 430*6e15146eSJoseph Chen } 431ffa8f8b7SJoseph Chen 432ffa8f8b7SJoseph Chen /* Add all available system memory */ 433ffa8f8b7SJoseph Chen #ifdef CONFIG_NR_DRAM_BANKS 434ffa8f8b7SJoseph Chen int i; 435ffa8f8b7SJoseph Chen 436ffa8f8b7SJoseph Chen for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 437*6e15146eSJoseph Chen if (!gd->bd->bi_dram[i].size) 438*6e15146eSJoseph Chen continue; 439*6e15146eSJoseph Chen 440ffa8f8b7SJoseph Chen ret = sysmem_add(gd->bd->bi_dram[i].start, 441ffa8f8b7SJoseph Chen gd->bd->bi_dram[i].size); 442ffa8f8b7SJoseph Chen if (ret) { 443ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bi_dram[%d]\n", i); 444*6e15146eSJoseph Chen goto fail; 445ffa8f8b7SJoseph Chen } 446ffa8f8b7SJoseph Chen } 447ffa8f8b7SJoseph Chen #else 448ffa8f8b7SJoseph Chen mem_start = env_get_bootm_low(); 449ffa8f8b7SJoseph Chen mem_size = env_get_bootm_size(); 450ffa8f8b7SJoseph Chen ret = sysmem_add(mem_start, mem_size); 451ffa8f8b7SJoseph Chen if (ret) { 452ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bootm_low/size\n"); 453*6e15146eSJoseph Chen goto fail; 454ffa8f8b7SJoseph Chen } 455ffa8f8b7SJoseph Chen #endif 456ffa8f8b7SJoseph Chen /* Reserved for board */ 457ffa8f8b7SJoseph Chen ret = board_sysmem_reserve(sysmem); 458ffa8f8b7SJoseph Chen if (ret) { 459ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for board\n"); 460*6e15146eSJoseph Chen goto fail; 461ffa8f8b7SJoseph Chen } 462ffa8f8b7SJoseph Chen 463*6e15146eSJoseph Chen /* Reserved for U-boot framework: 'reserve_xxx()' */ 464*6e15146eSJoseph Chen mem_start = gd->start_addr_sp; 465ffa8f8b7SJoseph Chen mem_size = gd->ram_top - mem_start; 466*6e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_UBOOT, mem_start, mem_size)) { 467ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for U-Boot framework\n"); 468*6e15146eSJoseph Chen ret = -ENOMEM; 469*6e15146eSJoseph Chen goto fail; 470ffa8f8b7SJoseph Chen } 471ffa8f8b7SJoseph Chen 472*6e15146eSJoseph Chen /* Reserved for U-Boot stack */ 473*6e15146eSJoseph Chen mem_start = gd->start_addr_sp - CONFIG_SYS_STACK_SIZE; 474*6e15146eSJoseph Chen mem_size = CONFIG_SYS_STACK_SIZE; 475*6e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_STACK, mem_start, mem_size)) { 476*6e15146eSJoseph Chen SYSMEM_E("Failed to reserve sysmem for stack\n"); 477*6e15146eSJoseph Chen ret = -ENOMEM; 478*6e15146eSJoseph Chen goto fail; 479*6e15146eSJoseph Chen } 480ffa8f8b7SJoseph Chen 481ffa8f8b7SJoseph Chen return 0; 482*6e15146eSJoseph Chen 483*6e15146eSJoseph Chen fail: 484*6e15146eSJoseph Chen if (ret && !(gd->flags & GD_FLG_RELOC)) { 485*6e15146eSJoseph Chen sysmem_dump(); 486*6e15146eSJoseph Chen SYSMEM_W("Maybe malloc size %d MiB is too large?\n\n", 487*6e15146eSJoseph Chen SIZE_MB(CONFIG_SYS_MALLOC_LEN)); 488*6e15146eSJoseph Chen } 489*6e15146eSJoseph Chen 490*6e15146eSJoseph Chen return ret; 491ffa8f8b7SJoseph Chen } 492ffa8f8b7SJoseph Chen 493ffa8f8b7SJoseph Chen __weak int board_sysmem_reserve(struct sysmem *sysmem) 494ffa8f8b7SJoseph Chen { 495ffa8f8b7SJoseph Chen /* please define platform specific board_sysmem_reserve() */ 496ffa8f8b7SJoseph Chen return 0; 497ffa8f8b7SJoseph Chen } 498ffa8f8b7SJoseph Chen 499*6e15146eSJoseph Chen static int do_dump_sysmem(cmd_tbl_t *cmdtp, int flag, 500*6e15146eSJoseph Chen int argc, char *const argv[]) 501ffa8f8b7SJoseph Chen { 502*6e15146eSJoseph Chen sysmem_dump(); 503ffa8f8b7SJoseph Chen return 0; 504ffa8f8b7SJoseph Chen } 505*6e15146eSJoseph Chen 506*6e15146eSJoseph Chen U_BOOT_CMD( 507*6e15146eSJoseph Chen dump_sysmem, 1, 1, do_dump_sysmem, 508*6e15146eSJoseph Chen "Dump sysmem layout", 509*6e15146eSJoseph Chen "" 510*6e15146eSJoseph Chen ); 511