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 #ifndef CONFIG_SYS_STACK_SIZE 19ffa8f8b7SJoseph Chen #define CONFIG_SYS_STACK_SIZE SZ_2M 20ffa8f8b7SJoseph Chen #endif 21ffa8f8b7SJoseph Chen 22ffa8f8b7SJoseph Chen #define SIZE_MB(len) ((len) >> 20) 23ffa8f8b7SJoseph Chen #define SIZE_KB(len) (((len) % (1 << 20)) >> 10) 24ffa8f8b7SJoseph Chen 25ffa8f8b7SJoseph Chen #define SYSMEM_I(fmt, args...) printf("Sysmem: "fmt, ##args) 26ffa8f8b7SJoseph Chen #define SYSMEM_W(fmt, args...) printf("Sysmem Warn: "fmt, ##args) 27ffa8f8b7SJoseph Chen #define SYSMEM_E(fmt, args...) printf("Sysmem Error: "fmt, ##args) 28ffa8f8b7SJoseph Chen #define SYSMEM_D(fmt, args...) debug("Sysmem Debug: "fmt, ##args) 29ffa8f8b7SJoseph Chen 30ffa8f8b7SJoseph Chen static struct sysmem plat_sysmem; /* Global for platform */ 31ffa8f8b7SJoseph Chen 32ffa8f8b7SJoseph Chen struct sysmem_check { 33ffa8f8b7SJoseph Chen uint32_t magic; 34ffa8f8b7SJoseph Chen }; 35ffa8f8b7SJoseph Chen 36ffa8f8b7SJoseph Chen static int sysmem_has_init(void) 37ffa8f8b7SJoseph Chen { 38ffa8f8b7SJoseph Chen if (!plat_sysmem.has_init) { 39ffa8f8b7SJoseph Chen SYSMEM_E("Framework is not initialized\n"); 40ffa8f8b7SJoseph Chen return 0; 41ffa8f8b7SJoseph Chen } 42ffa8f8b7SJoseph Chen 43ffa8f8b7SJoseph Chen return 1; 44ffa8f8b7SJoseph Chen } 45ffa8f8b7SJoseph Chen 46ffa8f8b7SJoseph Chen void sysmem_dump(void) 47ffa8f8b7SJoseph Chen { 48ffa8f8b7SJoseph Chen #ifdef DEBUG 49ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 50ffa8f8b7SJoseph Chen struct lmb *lmb = &sysmem->lmb; 51ffa8f8b7SJoseph Chen struct sysmem_property *prop; 52ffa8f8b7SJoseph Chen struct sysmem_check *check; 53ffa8f8b7SJoseph Chen struct list_head *node; 54ffa8f8b7SJoseph Chen ulong memory_size = 0; 55ffa8f8b7SJoseph Chen ulong reserved_size = 0; 56ffa8f8b7SJoseph Chen ulong allocated_size = 0; 57ffa8f8b7SJoseph Chen ulong i; 58ffa8f8b7SJoseph Chen 59ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 60ffa8f8b7SJoseph Chen return; 61ffa8f8b7SJoseph Chen 62ffa8f8b7SJoseph Chen printf("\nsysmem_dump_all:\n"); 63ffa8f8b7SJoseph Chen 64ffa8f8b7SJoseph Chen /* Memory pool */ 65ffa8f8b7SJoseph Chen printf(" ------------------------------------------------------\n"); 66ffa8f8b7SJoseph Chen for (i = 0; i < lmb->memory.cnt; i++) { 67ffa8f8b7SJoseph Chen memory_size += lmb->memory.region[i].size; 68ffa8f8b7SJoseph Chen printf(" memory.rgn[%ld].base = 0x%08lx\n", i, 69ffa8f8b7SJoseph Chen (ulong)lmb->memory.region[i].base); 70ffa8f8b7SJoseph Chen printf(" .size = 0x%08lx\n", 71ffa8f8b7SJoseph Chen (ulong)lmb->memory.region[i].size); 72ffa8f8b7SJoseph Chen } 73ffa8f8b7SJoseph Chen printf("\n memory.total = 0x%08lx (%ld MiB. %ld KiB)\n", 74ffa8f8b7SJoseph Chen (ulong)memory_size, 75ffa8f8b7SJoseph Chen SIZE_MB((ulong)memory_size), 76ffa8f8b7SJoseph Chen SIZE_KB((ulong)memory_size)); 77ffa8f8b7SJoseph Chen 78ffa8f8b7SJoseph Chen /* Reserved */ 79ffa8f8b7SJoseph Chen i = 0; 80ffa8f8b7SJoseph Chen printf(" ------------------------------------------------------\n"); 81ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->reserved_head) { 82ffa8f8b7SJoseph Chen prop = list_entry(node, struct sysmem_property, node); 83ffa8f8b7SJoseph Chen reserved_size += prop->size; 84ffa8f8b7SJoseph Chen printf(" reserved.rgn[%ld].name = \"%s\"\n", i, prop->name); 85ffa8f8b7SJoseph Chen printf(" .base = 0x%08lx\n", 86ffa8f8b7SJoseph Chen (ulong)prop->base); 87ffa8f8b7SJoseph Chen printf(" .size = 0x%08lx\n", 88ffa8f8b7SJoseph Chen (ulong)prop->size); 89ffa8f8b7SJoseph Chen i++; 90ffa8f8b7SJoseph Chen } 91ffa8f8b7SJoseph Chen printf("\n reserved.total = 0x%08lx (%ld MiB. %ld KiB)\n", 92ffa8f8b7SJoseph Chen (ulong)reserved_size, 93ffa8f8b7SJoseph Chen SIZE_MB((ulong)reserved_size), 94ffa8f8b7SJoseph Chen SIZE_KB((ulong)reserved_size)); 95ffa8f8b7SJoseph Chen 96ffa8f8b7SJoseph Chen /* Allocated */ 97ffa8f8b7SJoseph Chen i = 0; 98ffa8f8b7SJoseph Chen printf(" ------------------------------------------------------\n"); 99ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 100ffa8f8b7SJoseph Chen prop = list_entry(node, struct sysmem_property, node); 101ffa8f8b7SJoseph Chen allocated_size += prop->size; 102ffa8f8b7SJoseph Chen check = (struct sysmem_check *) 103ffa8f8b7SJoseph Chen (prop->base + prop->size - sizeof(*check)); 104ffa8f8b7SJoseph Chen printf(" allocated.rgn[%ld].name = \"%s\"%s\n", 105ffa8f8b7SJoseph Chen i, prop->name, 106ffa8f8b7SJoseph Chen check->magic != SYSMEM_MAGIC ? " (Overflow)" : ""); 107ffa8f8b7SJoseph Chen printf(" .base = 0x%08lx\n", 108ffa8f8b7SJoseph Chen (ulong)prop->base); 109ffa8f8b7SJoseph Chen printf(" .size = 0x%08lx\n", 110ffa8f8b7SJoseph Chen (ulong)prop->size); 111ffa8f8b7SJoseph Chen i++; 112ffa8f8b7SJoseph Chen } 113ffa8f8b7SJoseph Chen printf("\n allocated.total = 0x%08lx (%ld MiB. %ld KiB)\n", 114ffa8f8b7SJoseph Chen (ulong)allocated_size, 115ffa8f8b7SJoseph Chen SIZE_MB((ulong)allocated_size), 116ffa8f8b7SJoseph Chen SIZE_KB((ulong)allocated_size)); 117ffa8f8b7SJoseph Chen 118ffa8f8b7SJoseph Chen /* LMB core reserved */ 119ffa8f8b7SJoseph Chen printf(" ------------------------------------------------------\n"); 120ffa8f8b7SJoseph Chen reserved_size = 0; 121ffa8f8b7SJoseph Chen for (i = 0; i < lmb->reserved.cnt; i++) { 122ffa8f8b7SJoseph Chen reserved_size += lmb->reserved.region[i].size; 123ffa8f8b7SJoseph Chen printf(" LMB.reserved[%ld].base = 0x%08lx\n", i, 124ffa8f8b7SJoseph Chen (ulong)lmb->reserved.region[i].base); 125ffa8f8b7SJoseph Chen printf(" .size = 0x%08lx\n", 126ffa8f8b7SJoseph Chen (ulong)lmb->reserved.region[i].size); 127ffa8f8b7SJoseph Chen } 128ffa8f8b7SJoseph Chen 129ffa8f8b7SJoseph Chen printf("\n reserved.core.total = 0x%08lx (%ld MiB. %ld KiB)\n", 130ffa8f8b7SJoseph Chen (ulong)reserved_size, 131ffa8f8b7SJoseph Chen SIZE_MB((ulong)reserved_size), 132ffa8f8b7SJoseph Chen SIZE_KB((ulong)reserved_size)); 133ffa8f8b7SJoseph Chen printf(" ------------------------------------------------------\n\n"); 134ffa8f8b7SJoseph Chen #endif 135ffa8f8b7SJoseph Chen } 136ffa8f8b7SJoseph Chen 137ffa8f8b7SJoseph Chen int sysmem_check(void) 138ffa8f8b7SJoseph Chen { 139ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 140ffa8f8b7SJoseph Chen struct sysmem_property *prop; 141ffa8f8b7SJoseph Chen struct sysmem_check *check; 142ffa8f8b7SJoseph Chen struct list_head *node; 143ffa8f8b7SJoseph Chen int ret = 0; 144ffa8f8b7SJoseph Chen 145ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 146ffa8f8b7SJoseph Chen return -ENOSYS; 147ffa8f8b7SJoseph Chen 148ffa8f8b7SJoseph Chen /* Check allocated */ 149ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 150ffa8f8b7SJoseph Chen prop = list_entry(node, struct sysmem_property, node); 151ffa8f8b7SJoseph Chen check = (struct sysmem_check *) 152ffa8f8b7SJoseph Chen (prop->base + prop->size - sizeof(*check)); 153ffa8f8b7SJoseph Chen if (check->magic != SYSMEM_MAGIC) { 154ffa8f8b7SJoseph Chen ret = -EOVERFLOW; 155ffa8f8b7SJoseph Chen SYSMEM_E("\"%s\" (base=0x%08lx, size=0x%lx) is Overflow!\n", 156ffa8f8b7SJoseph Chen prop->name, (ulong)prop->base, (ulong)prop->size); 157ffa8f8b7SJoseph Chen } 158ffa8f8b7SJoseph Chen } 159ffa8f8b7SJoseph Chen 160ffa8f8b7SJoseph Chen /* Check stack */ 161ffa8f8b7SJoseph Chen check = (struct sysmem_check *)(gd->start_addr_sp - CONFIG_SYS_STACK_SIZE); 162ffa8f8b7SJoseph Chen if (check->magic != SYSMEM_MAGIC) { 163ffa8f8b7SJoseph Chen ret = -EOVERFLOW; 164ffa8f8b7SJoseph Chen SYSMEM_E("Runtime stack is Overflow!\n"); 165ffa8f8b7SJoseph Chen } 166ffa8f8b7SJoseph Chen 167ffa8f8b7SJoseph Chen return ret; 168ffa8f8b7SJoseph Chen } 169ffa8f8b7SJoseph Chen 170ffa8f8b7SJoseph Chen int sysmem_dump_check(void) 171ffa8f8b7SJoseph Chen { 172ffa8f8b7SJoseph Chen sysmem_dump(); 173ffa8f8b7SJoseph Chen 174ffa8f8b7SJoseph Chen return sysmem_check(); 175ffa8f8b7SJoseph Chen } 176ffa8f8b7SJoseph Chen 177ffa8f8b7SJoseph Chen static int sysmem_is_overlap(phys_addr_t base1, phys_size_t size1, 178ffa8f8b7SJoseph Chen phys_addr_t base2, phys_size_t size2) 179ffa8f8b7SJoseph Chen { 180ffa8f8b7SJoseph Chen return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); 181ffa8f8b7SJoseph Chen } 182ffa8f8b7SJoseph Chen 183ffa8f8b7SJoseph Chen int sysmem_add(phys_addr_t base, phys_size_t size) 184ffa8f8b7SJoseph Chen { 185ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 186ffa8f8b7SJoseph Chen int ret; 187ffa8f8b7SJoseph Chen 188ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 189ffa8f8b7SJoseph Chen return -ENOSYS; 190ffa8f8b7SJoseph Chen 191ffa8f8b7SJoseph Chen ret = lmb_add(&sysmem->lmb, base, size); 192ffa8f8b7SJoseph Chen if (ret < 0) 193ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem at 0x%lx for 0x%lx size\n", 194ffa8f8b7SJoseph Chen (ulong)base, (ulong)size); 195ffa8f8b7SJoseph Chen 196ffa8f8b7SJoseph Chen return (ret >= 0) ? 0 : ret; 197ffa8f8b7SJoseph Chen } 198ffa8f8b7SJoseph Chen 199ffa8f8b7SJoseph Chen int sysmem_reserve(const char *name, phys_addr_t base, phys_size_t size) 200ffa8f8b7SJoseph Chen { 201ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 202ffa8f8b7SJoseph Chen struct sysmem_property *prop; 203ffa8f8b7SJoseph Chen struct list_head *node; 204ffa8f8b7SJoseph Chen int ret = 0; 205ffa8f8b7SJoseph Chen 206ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 207ffa8f8b7SJoseph Chen return -ENOSYS; 208ffa8f8b7SJoseph Chen 209ffa8f8b7SJoseph Chen if (!name) { 210ffa8f8b7SJoseph Chen SYSMEM_E("NULL name for reserved sysmem\n"); 211ffa8f8b7SJoseph Chen return -EINVAL; 212ffa8f8b7SJoseph Chen } 213ffa8f8b7SJoseph Chen 214ffa8f8b7SJoseph Chen /* Check overlap */ 215ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->reserved_head) { 216ffa8f8b7SJoseph Chen prop = list_entry(node, struct sysmem_property, node); 217ffa8f8b7SJoseph Chen if (!strcmp(prop->name, name)) { 218ffa8f8b7SJoseph Chen SYSMEM_E("Failed to double reserve for existence \"%s\"\n", name); 219ffa8f8b7SJoseph Chen return -EEXIST; 220ffa8f8b7SJoseph Chen } else if (sysmem_is_overlap(prop->base, prop->size, base, size)) { 2213befe43dSJoseph Chen SYSMEM_D("\"%s\" (base=0x%08lx, size=0x%lx) reserve is " 222ffa8f8b7SJoseph Chen "overlap with existence \"%s\" (base=0x%08lx, size=0x%lx)\n", 223ffa8f8b7SJoseph Chen name, (ulong)base, (ulong)size, prop->name, 224ffa8f8b7SJoseph Chen (ulong)prop->base, (ulong)prop->size); 225ffa8f8b7SJoseph Chen } 226ffa8f8b7SJoseph Chen } 227ffa8f8b7SJoseph Chen 228ffa8f8b7SJoseph Chen ret = lmb_reserve(&sysmem->lmb, base, size); 229ffa8f8b7SJoseph Chen if (ret >= 0) { 230ffa8f8b7SJoseph Chen prop = malloc(sizeof(*prop)); 231ffa8f8b7SJoseph Chen if (!prop) { 232ffa8f8b7SJoseph Chen SYSMEM_E("No memory for \"%s\" reserve sysmem\n", name); 233ffa8f8b7SJoseph Chen return -ENOMEM; 234ffa8f8b7SJoseph Chen } 235ffa8f8b7SJoseph Chen 236ffa8f8b7SJoseph Chen prop->name = name; 237ffa8f8b7SJoseph Chen prop->base = base; 238ffa8f8b7SJoseph Chen prop->size = size; 239ffa8f8b7SJoseph Chen list_add_tail(&prop->node, &sysmem->reserved_head); 240ffa8f8b7SJoseph Chen } else { 241ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve \"%s\" at 0x%lx\n", name, (ulong)base); 242ffa8f8b7SJoseph Chen return -EINVAL; 243ffa8f8b7SJoseph Chen } 244ffa8f8b7SJoseph Chen 245ffa8f8b7SJoseph Chen return 0; 246ffa8f8b7SJoseph Chen } 247ffa8f8b7SJoseph Chen 248ffa8f8b7SJoseph Chen void *sysmem_alloc_align_base(const char *name, 249ffa8f8b7SJoseph Chen phys_addr_t base, 250ffa8f8b7SJoseph Chen phys_size_t size, 251ffa8f8b7SJoseph Chen ulong align) 252ffa8f8b7SJoseph Chen { 253ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 254ffa8f8b7SJoseph Chen struct sysmem_property *prop; 255ffa8f8b7SJoseph Chen struct sysmem_check *check; 256ffa8f8b7SJoseph Chen struct list_head *node; 257ffa8f8b7SJoseph Chen phys_addr_t paddr; 258ffa8f8b7SJoseph Chen phys_addr_t alloc_base; 259ffa8f8b7SJoseph Chen phys_size_t alloc_size; 260ffa8f8b7SJoseph Chen 261ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 262ffa8f8b7SJoseph Chen return NULL; 263ffa8f8b7SJoseph Chen 264ffa8f8b7SJoseph Chen if (!name) { 265ffa8f8b7SJoseph Chen SYSMEM_E("NULL name for alloc sysmem\n"); 266ffa8f8b7SJoseph Chen return NULL; 267ffa8f8b7SJoseph Chen } 268ffa8f8b7SJoseph Chen 269ffa8f8b7SJoseph Chen /* Already allocated ? */ 270ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 271ffa8f8b7SJoseph Chen prop = list_entry(node, struct sysmem_property, node); 272ffa8f8b7SJoseph Chen if (!strcmp(prop->name, name)) { 273ffa8f8b7SJoseph Chen SYSMEM_E("Failed to double alloc for existence \"%s\"\n", name); 274ffa8f8b7SJoseph Chen return NULL; 275ffa8f8b7SJoseph Chen } else if (sysmem_is_overlap(prop->base, prop->size, base, size)) { 276ffa8f8b7SJoseph Chen SYSMEM_E("\"%s\" (base=0x%08lx, size=0x%lx) alloc is " 277ffa8f8b7SJoseph Chen "overlap with existence \"%s\" (base=0x%08lx, size=0x%lx)\n", 278ffa8f8b7SJoseph Chen name, (ulong)base, (ulong)size, 279ffa8f8b7SJoseph Chen prop->name, (ulong)prop->base, 280ffa8f8b7SJoseph Chen (ulong)prop->size); 281ffa8f8b7SJoseph Chen return NULL; 282ffa8f8b7SJoseph Chen } 283ffa8f8b7SJoseph Chen } 284ffa8f8b7SJoseph Chen 285ffa8f8b7SJoseph Chen alloc_size = size + sizeof(*check); 286ffa8f8b7SJoseph Chen if (base == SYSMEM_ALLOC_ANYWHERE) 287ffa8f8b7SJoseph Chen alloc_base = base; 288ffa8f8b7SJoseph Chen else 289ffa8f8b7SJoseph Chen alloc_base = base + alloc_size; /* LMB is align down alloc mechanism */ 290ffa8f8b7SJoseph Chen 291ffa8f8b7SJoseph Chen paddr = lmb_alloc_base(&sysmem->lmb, alloc_size, align, alloc_base); 292ffa8f8b7SJoseph Chen if (paddr) { 293ffa8f8b7SJoseph Chen if ((paddr == base) || (base == SYSMEM_ALLOC_ANYWHERE)) { 294ffa8f8b7SJoseph Chen prop = malloc(sizeof(*prop)); 295ffa8f8b7SJoseph Chen if (!prop) { 296ffa8f8b7SJoseph Chen SYSMEM_E("No memory for \"%s\" alloc sysmem\n", name); 297ffa8f8b7SJoseph Chen return NULL; 298ffa8f8b7SJoseph Chen } 299ffa8f8b7SJoseph Chen 300ffa8f8b7SJoseph Chen prop->name = name; 301ffa8f8b7SJoseph Chen prop->base = paddr; 302ffa8f8b7SJoseph Chen prop->size = alloc_size; 303ffa8f8b7SJoseph Chen sysmem->allocated_cnt++; 304ffa8f8b7SJoseph Chen 305ffa8f8b7SJoseph Chen check = (struct sysmem_check *)(paddr + size); 306ffa8f8b7SJoseph Chen check->magic = SYSMEM_MAGIC; 307ffa8f8b7SJoseph Chen 308ffa8f8b7SJoseph Chen list_add_tail(&prop->node, &sysmem->allocated_head); 309ffa8f8b7SJoseph Chen } else { 310ffa8f8b7SJoseph Chen SYSMEM_E("Failed to alloc \"%s\" at expect 0x%lx but " 311ffa8f8b7SJoseph Chen "alloc at 0x%lx\n", 312ffa8f8b7SJoseph Chen name, (ulong)base, (ulong)paddr); 313ffa8f8b7SJoseph Chen return NULL; 314ffa8f8b7SJoseph Chen } 315ffa8f8b7SJoseph Chen } else { 316ffa8f8b7SJoseph Chen SYSMEM_E("Failed to alloc \"%s\" at 0x%lx\n", name, (ulong)base); 317ffa8f8b7SJoseph Chen } 318ffa8f8b7SJoseph Chen 319ffa8f8b7SJoseph Chen SYSMEM_D("Alloc: \"%s\", paddr=0x%lx, size=0x%lx, align=0x%x, anywhere=%d\n", 320ffa8f8b7SJoseph Chen name, (ulong)paddr, (ulong)size, (u32)align, !base); 321ffa8f8b7SJoseph Chen 322ffa8f8b7SJoseph Chen return (void *)paddr; 323ffa8f8b7SJoseph Chen } 324ffa8f8b7SJoseph Chen 325ffa8f8b7SJoseph Chen void *sysmem_alloc_align(const char *name, phys_size_t size, ulong align) 326ffa8f8b7SJoseph Chen { 327ffa8f8b7SJoseph Chen return sysmem_alloc_align_base(name, 328ffa8f8b7SJoseph Chen SYSMEM_ALLOC_ANYWHERE, 329ffa8f8b7SJoseph Chen size, 330ffa8f8b7SJoseph Chen align); 331ffa8f8b7SJoseph Chen } 332ffa8f8b7SJoseph Chen 333ffa8f8b7SJoseph Chen void *sysmem_alloc_base(const char *name, phys_addr_t base, phys_size_t size) 334ffa8f8b7SJoseph Chen { 335ffa8f8b7SJoseph Chen return sysmem_alloc_align_base(name, 336ffa8f8b7SJoseph Chen base, 337ffa8f8b7SJoseph Chen size, 338ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 339ffa8f8b7SJoseph Chen } 340ffa8f8b7SJoseph Chen 341ffa8f8b7SJoseph Chen void *sysmem_alloc(const char *name, phys_size_t size) 342ffa8f8b7SJoseph Chen { 343ffa8f8b7SJoseph Chen return sysmem_alloc_align_base(name, 344ffa8f8b7SJoseph Chen SYSMEM_ALLOC_ANYWHERE, 345ffa8f8b7SJoseph Chen size, 346ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 347ffa8f8b7SJoseph Chen } 348ffa8f8b7SJoseph Chen 349ffa8f8b7SJoseph Chen int sysmem_free(phys_addr_t base) 350ffa8f8b7SJoseph Chen { 351ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 352ffa8f8b7SJoseph Chen struct sysmem_property *prop; 353ffa8f8b7SJoseph Chen struct list_head *node; 354ffa8f8b7SJoseph Chen int found = 0; 355ffa8f8b7SJoseph Chen int ret; 356ffa8f8b7SJoseph Chen 357ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 358ffa8f8b7SJoseph Chen return -ENOSYS; 359ffa8f8b7SJoseph Chen 360ffa8f8b7SJoseph Chen /* Find existence */ 361ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 362ffa8f8b7SJoseph Chen prop = list_entry(node, struct sysmem_property, node); 363ffa8f8b7SJoseph Chen if (prop->base == base) { 364ffa8f8b7SJoseph Chen found = 1; 365ffa8f8b7SJoseph Chen break; 366ffa8f8b7SJoseph Chen } 367ffa8f8b7SJoseph Chen } 368ffa8f8b7SJoseph Chen 369ffa8f8b7SJoseph Chen if (!found) { 370ffa8f8b7SJoseph Chen SYSMEM_E("Failed to free no allocated sysmem at 0x%lx\n", (ulong)base); 371ffa8f8b7SJoseph Chen return -EINVAL; 372ffa8f8b7SJoseph Chen } 373ffa8f8b7SJoseph Chen 374ffa8f8b7SJoseph Chen ret = lmb_free(&sysmem->lmb, prop->base, prop->size); 375ffa8f8b7SJoseph Chen if (ret >= 0) { 376*2c9d1179SJoseph Chen SYSMEM_D("Free: \"%s\", paddr=0x%lx, size=0x%lx\n", 377ffa8f8b7SJoseph Chen prop->name, (ulong)prop->base, (ulong)prop->size); 378ffa8f8b7SJoseph Chen sysmem->allocated_cnt--; 379ffa8f8b7SJoseph Chen list_del(&prop->node); 380ffa8f8b7SJoseph Chen free(prop); 381ffa8f8b7SJoseph Chen } else { 382ffa8f8b7SJoseph Chen SYSMEM_E("Failed to free \"%s\" at 0x%lx\n", prop->name, (ulong)base); 383ffa8f8b7SJoseph Chen } 384ffa8f8b7SJoseph Chen 385ffa8f8b7SJoseph Chen return (ret >= 0) ? 0 : ret; 386ffa8f8b7SJoseph Chen } 387ffa8f8b7SJoseph Chen 388ffa8f8b7SJoseph Chen int sysmem_init(void) 389ffa8f8b7SJoseph Chen { 390ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 391ffa8f8b7SJoseph Chen struct sysmem_check *check; 392ffa8f8b7SJoseph Chen phys_addr_t mem_start; 393ffa8f8b7SJoseph Chen phys_size_t mem_size; 394ffa8f8b7SJoseph Chen int ret; 395ffa8f8b7SJoseph Chen 396ffa8f8b7SJoseph Chen SYSMEM_I("init\n"); 397ffa8f8b7SJoseph Chen 398ffa8f8b7SJoseph Chen lmb_init(&sysmem->lmb); 399ffa8f8b7SJoseph Chen INIT_LIST_HEAD(&sysmem->allocated_head); 400ffa8f8b7SJoseph Chen INIT_LIST_HEAD(&sysmem->reserved_head); 401ffa8f8b7SJoseph Chen sysmem->allocated_cnt = 0; 402ffa8f8b7SJoseph Chen sysmem->has_init = true; 403ffa8f8b7SJoseph Chen 404ffa8f8b7SJoseph Chen /* Add all available system memory */ 405ffa8f8b7SJoseph Chen #ifdef CONFIG_NR_DRAM_BANKS 406ffa8f8b7SJoseph Chen int i; 407ffa8f8b7SJoseph Chen 408ffa8f8b7SJoseph Chen for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 409ffa8f8b7SJoseph Chen ret = sysmem_add(gd->bd->bi_dram[i].start, 410ffa8f8b7SJoseph Chen gd->bd->bi_dram[i].size); 411ffa8f8b7SJoseph Chen if (ret) { 412ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bi_dram[%d]\n", i); 413ffa8f8b7SJoseph Chen return ret; 414ffa8f8b7SJoseph Chen } 415ffa8f8b7SJoseph Chen } 416ffa8f8b7SJoseph Chen #else 417ffa8f8b7SJoseph Chen mem_start = env_get_bootm_low(); 418ffa8f8b7SJoseph Chen mem_size = env_get_bootm_size(); 419ffa8f8b7SJoseph Chen ret = sysmem_add(mem_start, mem_size); 420ffa8f8b7SJoseph Chen if (ret) { 421ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bootm_low/size\n"); 422ffa8f8b7SJoseph Chen return ret; 423ffa8f8b7SJoseph Chen } 424ffa8f8b7SJoseph Chen #endif 425ffa8f8b7SJoseph Chen 426ffa8f8b7SJoseph Chen /* Reserved for arch */ 427ffa8f8b7SJoseph Chen ret = arch_sysmem_reserve(sysmem); 428ffa8f8b7SJoseph Chen if (ret) { 429ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for arch\n"); 430ffa8f8b7SJoseph Chen return ret; 431ffa8f8b7SJoseph Chen } 432ffa8f8b7SJoseph Chen 433ffa8f8b7SJoseph Chen /* Reserved for board */ 434ffa8f8b7SJoseph Chen ret = board_sysmem_reserve(sysmem); 435ffa8f8b7SJoseph Chen if (ret) { 436ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for board\n"); 437ffa8f8b7SJoseph Chen return ret; 438ffa8f8b7SJoseph Chen } 439ffa8f8b7SJoseph Chen 440ffa8f8b7SJoseph Chen /* Reserved for U-boot framework 'reserve_xxx()' */ 441ffa8f8b7SJoseph Chen mem_start = gd->start_addr_sp - CONFIG_SYS_STACK_SIZE; 442ffa8f8b7SJoseph Chen mem_size = gd->ram_top - mem_start; 443ffa8f8b7SJoseph Chen check = (struct sysmem_check *)mem_start; 444ffa8f8b7SJoseph Chen check->magic = SYSMEM_MAGIC; 445ffa8f8b7SJoseph Chen 446ffa8f8b7SJoseph Chen ret = sysmem_reserve("U-Boot", mem_start, mem_size); 447ffa8f8b7SJoseph Chen if (ret) { 448ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for U-Boot framework\n"); 449ffa8f8b7SJoseph Chen return ret; 450ffa8f8b7SJoseph Chen } 451ffa8f8b7SJoseph Chen 452ffa8f8b7SJoseph Chen sysmem_dump(); 453ffa8f8b7SJoseph Chen 454ffa8f8b7SJoseph Chen return 0; 455ffa8f8b7SJoseph Chen } 456ffa8f8b7SJoseph Chen 457ffa8f8b7SJoseph Chen __weak int board_sysmem_reserve(struct sysmem *sysmem) 458ffa8f8b7SJoseph Chen { 459ffa8f8b7SJoseph Chen /* please define platform specific board_sysmem_reserve() */ 460ffa8f8b7SJoseph Chen return 0; 461ffa8f8b7SJoseph Chen } 462ffa8f8b7SJoseph Chen 463ffa8f8b7SJoseph Chen __weak int arch_sysmem_reserve(struct sysmem *sysmem) 464ffa8f8b7SJoseph Chen { 465ffa8f8b7SJoseph Chen /* please define platform specific arch_sysmem_reserve() */ 466ffa8f8b7SJoseph Chen return 0; 467ffa8f8b7SJoseph Chen } 468