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" */ 15598774ecSJoseph Chen 16598774ecSJoseph Chen #define LMB_ALLOC_ANYWHERE 0 /* sync with lmb.c */ 17ffa8f8b7SJoseph Chen #define SYSMEM_ALLOC_NO_ALIGN 1 18598774ecSJoseph Chen #define SYSMEM_ALLOC_ANYWHERE 2 19ffa8f8b7SJoseph Chen 20ffa8f8b7SJoseph Chen #define SYSMEM_I(fmt, args...) printf("Sysmem: "fmt, ##args) 21ffa8f8b7SJoseph Chen #define SYSMEM_W(fmt, args...) printf("Sysmem Warn: "fmt, ##args) 22ffa8f8b7SJoseph Chen #define SYSMEM_E(fmt, args...) printf("Sysmem Error: "fmt, ##args) 23ffa8f8b7SJoseph Chen #define SYSMEM_D(fmt, args...) debug("Sysmem Debug: "fmt, ##args) 24ffa8f8b7SJoseph Chen 256e15146eSJoseph Chen struct memcheck { 26ffa8f8b7SJoseph Chen uint32_t magic; 27ffa8f8b7SJoseph Chen }; 28ffa8f8b7SJoseph Chen 296e15146eSJoseph Chen /* Global for platform, must in data section */ 306e15146eSJoseph Chen struct sysmem plat_sysmem __section(".data") = { 316e15146eSJoseph Chen .has_initf = false, 326e15146eSJoseph Chen .has_initr = false, 336e15146eSJoseph Chen }; 34ffa8f8b7SJoseph Chen 356e15146eSJoseph Chen bool sysmem_has_init(void) 366e15146eSJoseph Chen { 376e15146eSJoseph Chen return gd->flags & GD_FLG_RELOC ? 386e15146eSJoseph Chen plat_sysmem.has_initr : plat_sysmem.has_initf; 39ffa8f8b7SJoseph Chen } 40ffa8f8b7SJoseph Chen 41ffa8f8b7SJoseph Chen void sysmem_dump(void) 42ffa8f8b7SJoseph Chen { 43ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 44ffa8f8b7SJoseph Chen struct lmb *lmb = &sysmem->lmb; 456e15146eSJoseph Chen struct memblock *mem; 466e15146eSJoseph Chen struct memcheck *check; 47ffa8f8b7SJoseph Chen struct list_head *node; 48ffa8f8b7SJoseph Chen ulong memory_size = 0; 49ffa8f8b7SJoseph Chen ulong reserved_size = 0; 50ffa8f8b7SJoseph Chen ulong allocated_size = 0; 516e15146eSJoseph Chen bool overflow = false; 52ffa8f8b7SJoseph Chen ulong i; 53ffa8f8b7SJoseph Chen 54ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 55ffa8f8b7SJoseph Chen return; 56ffa8f8b7SJoseph Chen 57ffa8f8b7SJoseph Chen printf("\nsysmem_dump_all:\n"); 58ffa8f8b7SJoseph Chen 59ffa8f8b7SJoseph Chen /* Memory pool */ 606e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n"); 61ffa8f8b7SJoseph Chen for (i = 0; i < lmb->memory.cnt; i++) { 62ffa8f8b7SJoseph Chen memory_size += lmb->memory.region[i].size; 636e15146eSJoseph Chen printf(" memory.rgn[%ld].addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", i, 646e15146eSJoseph Chen (ulong)lmb->memory.region[i].base, 656e15146eSJoseph Chen (ulong)lmb->memory.region[i].base + 666e15146eSJoseph Chen (ulong)lmb->memory.region[i].size, 67ffa8f8b7SJoseph Chen (ulong)lmb->memory.region[i].size); 68ffa8f8b7SJoseph Chen } 69ffa8f8b7SJoseph Chen printf("\n memory.total = 0x%08lx (%ld MiB. %ld KiB)\n", 70ffa8f8b7SJoseph Chen (ulong)memory_size, 71ffa8f8b7SJoseph Chen SIZE_MB((ulong)memory_size), 72ffa8f8b7SJoseph Chen SIZE_KB((ulong)memory_size)); 73ffa8f8b7SJoseph Chen 74ffa8f8b7SJoseph Chen /* Allocated */ 75ffa8f8b7SJoseph Chen i = 0; 766e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n"); 77ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 786e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 796e15146eSJoseph Chen allocated_size += mem->size; 806e15146eSJoseph Chen if (mem->attr.flags & M_ATTR_OFC) { 816e15146eSJoseph Chen check = (struct memcheck *) 826e15146eSJoseph Chen (mem->base + mem->size - sizeof(*check)); 836e15146eSJoseph Chen overflow = (check->magic != SYSMEM_MAGIC); 846e15146eSJoseph Chen } else if (mem->attr.flags & M_ATTR_HOFC) { 856e15146eSJoseph Chen check = (struct memcheck *) 866e15146eSJoseph Chen (mem->base - sizeof(*check)); 876e15146eSJoseph Chen overflow = (check->magic != SYSMEM_MAGIC); 886e15146eSJoseph Chen } else { 896e15146eSJoseph Chen overflow = false; 906e15146eSJoseph Chen } 916e15146eSJoseph Chen 92ffa8f8b7SJoseph Chen printf(" allocated.rgn[%ld].name = \"%s\" %s\n", 936e15146eSJoseph Chen i, mem->attr.name, overflow ? " <Overflow!>" : ""); 946e15146eSJoseph Chen printf(" .addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", 956e15146eSJoseph Chen (ulong)mem->base, (ulong)(mem->base + mem->size), 966e15146eSJoseph Chen (ulong)mem->size); 97ffa8f8b7SJoseph Chen i++; 98ffa8f8b7SJoseph Chen } 996e15146eSJoseph Chen 1006e15146eSJoseph Chen printf("\n malloc_r: %d MiB, malloc_f: %d KiB\n", 1016e15146eSJoseph Chen SIZE_MB(CONFIG_SYS_MALLOC_LEN), SIZE_KB(CONFIG_SYS_MALLOC_F_LEN)); 102ffa8f8b7SJoseph Chen printf("\n allocated.total = 0x%08lx (%ld MiB. %ld KiB)\n", 103ffa8f8b7SJoseph Chen (ulong)allocated_size, 104ffa8f8b7SJoseph Chen SIZE_MB((ulong)allocated_size), 105ffa8f8b7SJoseph Chen SIZE_KB((ulong)allocated_size)); 106ffa8f8b7SJoseph Chen 107ffa8f8b7SJoseph Chen /* LMB core reserved */ 1086e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n"); 109ffa8f8b7SJoseph Chen reserved_size = 0; 110ffa8f8b7SJoseph Chen for (i = 0; i < lmb->reserved.cnt; i++) { 111ffa8f8b7SJoseph Chen reserved_size += lmb->reserved.region[i].size; 1126e15146eSJoseph Chen printf(" LMB.reserved[%ld].addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", i, 1136e15146eSJoseph Chen (ulong)lmb->reserved.region[i].base, 1146e15146eSJoseph Chen (ulong)lmb->reserved.region[i].base + 1156e15146eSJoseph Chen (ulong)lmb->reserved.region[i].size, 116ffa8f8b7SJoseph Chen (ulong)lmb->reserved.region[i].size); 117ffa8f8b7SJoseph Chen } 118ffa8f8b7SJoseph Chen 119ffa8f8b7SJoseph Chen printf("\n reserved.core.total = 0x%08lx (%ld MiB. %ld KiB)\n", 120ffa8f8b7SJoseph Chen (ulong)reserved_size, 121ffa8f8b7SJoseph Chen SIZE_MB((ulong)reserved_size), 122ffa8f8b7SJoseph Chen SIZE_KB((ulong)reserved_size)); 1236e15146eSJoseph Chen printf(" --------------------------------------------------------------------\n\n"); 124ffa8f8b7SJoseph Chen } 125ffa8f8b7SJoseph Chen 126*2c66f6f3SJoseph Chen void sysmem_overflow_check(void) 127*2c66f6f3SJoseph Chen { 128*2c66f6f3SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 129*2c66f6f3SJoseph Chen struct list_head *node; 130*2c66f6f3SJoseph Chen struct memcheck *check; 131*2c66f6f3SJoseph Chen struct memblock *mem; 132*2c66f6f3SJoseph Chen int overflow; 133*2c66f6f3SJoseph Chen 134*2c66f6f3SJoseph Chen if (!sysmem_has_init()) 135*2c66f6f3SJoseph Chen return; 136*2c66f6f3SJoseph Chen 137*2c66f6f3SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 138*2c66f6f3SJoseph Chen mem = list_entry(node, struct memblock, node); 139*2c66f6f3SJoseph Chen if (mem->attr.flags & M_ATTR_OFC) { 140*2c66f6f3SJoseph Chen check = (struct memcheck *) 141*2c66f6f3SJoseph Chen (mem->base + mem->size - sizeof(*check)); 142*2c66f6f3SJoseph Chen overflow = (check->magic != SYSMEM_MAGIC); 143*2c66f6f3SJoseph Chen } else if (mem->attr.flags & M_ATTR_HOFC) { 144*2c66f6f3SJoseph Chen check = (struct memcheck *) 145*2c66f6f3SJoseph Chen (mem->base - sizeof(*check)); 146*2c66f6f3SJoseph Chen overflow = (check->magic != SYSMEM_MAGIC); 147*2c66f6f3SJoseph Chen } else { 148*2c66f6f3SJoseph Chen overflow = 0; 149*2c66f6f3SJoseph Chen } 150*2c66f6f3SJoseph Chen 151*2c66f6f3SJoseph Chen if (overflow) 152*2c66f6f3SJoseph Chen break; 153*2c66f6f3SJoseph Chen } 154*2c66f6f3SJoseph Chen 155*2c66f6f3SJoseph Chen if (overflow) { 156*2c66f6f3SJoseph Chen SYSMEM_E("Found there is region overflow!\n"); 157*2c66f6f3SJoseph Chen sysmem_dump(); 158*2c66f6f3SJoseph Chen } 159*2c66f6f3SJoseph Chen } 160*2c66f6f3SJoseph Chen 1616e15146eSJoseph Chen static inline int sysmem_is_overlap(phys_addr_t base1, phys_size_t size1, 162ffa8f8b7SJoseph Chen phys_addr_t base2, phys_size_t size2) 163ffa8f8b7SJoseph Chen { 164ffa8f8b7SJoseph Chen return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); 165ffa8f8b7SJoseph Chen } 166ffa8f8b7SJoseph Chen 1676e15146eSJoseph Chen static int sysmem_add(phys_addr_t base, phys_size_t size) 168ffa8f8b7SJoseph Chen { 169ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 170ffa8f8b7SJoseph Chen int ret; 171ffa8f8b7SJoseph Chen 1726e15146eSJoseph Chen if (!size) 1736e15146eSJoseph Chen return -EINVAL; 174ffa8f8b7SJoseph Chen 175ffa8f8b7SJoseph Chen ret = lmb_add(&sysmem->lmb, base, size); 176ffa8f8b7SJoseph Chen if (ret < 0) 1776e15146eSJoseph Chen SYSMEM_E("Failed to add sysmem at 0x%08lx for 0x%08lx size\n", 178ffa8f8b7SJoseph Chen (ulong)base, (ulong)size); 179ffa8f8b7SJoseph Chen 180ffa8f8b7SJoseph Chen return (ret >= 0) ? 0 : ret; 181ffa8f8b7SJoseph Chen } 182ffa8f8b7SJoseph Chen 1836e15146eSJoseph Chen static const char *sysmem_alias2name(const char *name, int *id) 184ffa8f8b7SJoseph Chen { 1856e15146eSJoseph Chen const char *alias; 1866e15146eSJoseph Chen int n, i, j; 1876e15146eSJoseph Chen int match = 0; 188ffa8f8b7SJoseph Chen 1896e15146eSJoseph Chen for (i = 0; i < MEMBLK_ID_MAX; i++) { 1906e15146eSJoseph Chen /* Pirmary name */ 1916e15146eSJoseph Chen if (mem_attr[i].name && !strcasecmp(mem_attr[i].name, name)) { 1926e15146eSJoseph Chen match = 1; 1936e15146eSJoseph Chen goto finish; 194ffa8f8b7SJoseph Chen } 195ffa8f8b7SJoseph Chen 1966e15146eSJoseph Chen /* Alias name */ 1976e15146eSJoseph Chen alias = mem_attr[i].alias[0]; 1986e15146eSJoseph Chen if (!alias) 1996e15146eSJoseph Chen continue; 2006e15146eSJoseph Chen 2016e15146eSJoseph Chen n = ARRAY_SIZE(mem_attr[i].alias); 2026e15146eSJoseph Chen for (j = 0; j < n; j++, alias++) { 2036e15146eSJoseph Chen if (alias && !strcasecmp(alias, name)) { 2046e15146eSJoseph Chen match = 1; 2056e15146eSJoseph Chen goto finish; 2066e15146eSJoseph Chen } 207ffa8f8b7SJoseph Chen } 208ffa8f8b7SJoseph Chen } 209ffa8f8b7SJoseph Chen 2106e15146eSJoseph Chen finish: 2116e15146eSJoseph Chen if (match) { 2126e15146eSJoseph Chen *id = i; 2136e15146eSJoseph Chen return mem_attr[i].name; 214ffa8f8b7SJoseph Chen } 215ffa8f8b7SJoseph Chen 2166e15146eSJoseph Chen return name; 217ffa8f8b7SJoseph Chen } 218ffa8f8b7SJoseph Chen 2196e15146eSJoseph Chen static void *sysmem_alloc_align_base(enum memblk_id id, 2206e15146eSJoseph Chen const char *mem_name, 221ffa8f8b7SJoseph Chen phys_addr_t base, 222ffa8f8b7SJoseph Chen phys_size_t size, 223ffa8f8b7SJoseph Chen ulong align) 224ffa8f8b7SJoseph Chen { 225ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 2266e15146eSJoseph Chen struct memblk_attr attr; 2276e15146eSJoseph Chen struct memblock *mem; 2286e15146eSJoseph Chen struct memcheck *check; 229ffa8f8b7SJoseph Chen struct list_head *node; 2306e15146eSJoseph Chen const char *name; 231ffa8f8b7SJoseph Chen phys_addr_t paddr; 232ffa8f8b7SJoseph Chen phys_addr_t alloc_base; 233ffa8f8b7SJoseph Chen phys_size_t alloc_size; 234305d8903SJoseph Chen phys_addr_t bank_base; 235305d8903SJoseph Chen phys_size_t bank_size; 236305d8903SJoseph Chen bool req_overlap = false; /* Only for kernel reserved-memory */ 237305d8903SJoseph Chen int i; 238ffa8f8b7SJoseph Chen 239ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 240efda1f1dSJoseph Chen goto out; 241ffa8f8b7SJoseph Chen 2426e15146eSJoseph Chen if (id == MEMBLK_ID_BY_NAME || id == MEMBLK_ID_FDT_RESV) { 2436e15146eSJoseph Chen if (!mem_name) { 244ffa8f8b7SJoseph Chen SYSMEM_E("NULL name for alloc sysmem\n"); 245efda1f1dSJoseph Chen goto out; 2466e15146eSJoseph Chen } else if (id == MEMBLK_ID_FDT_RESV) { 247efda1f1dSJoseph Chen 248efda1f1dSJoseph Chen /* 249efda1f1dSJoseph Chen * Allow fdt reserved memory to overlap with the region 250efda1f1dSJoseph Chen * only used in U-Boot, like: stack, fastboot, u-boot... 251efda1f1dSJoseph Chen * these regions are marked as M_ATTR_OVERLAP in flags. 252efda1f1dSJoseph Chen * 253efda1f1dSJoseph Chen * Here we check whether it overlaps with others, if 254efda1f1dSJoseph Chen * so, set req_overlap as true. 255efda1f1dSJoseph Chen */ 256305d8903SJoseph Chen for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 257305d8903SJoseph Chen if (!gd->bd->bi_dram[i].size) 258305d8903SJoseph Chen continue; 259305d8903SJoseph Chen 260305d8903SJoseph Chen bank_base = gd->bd->bi_dram[i].start; 261305d8903SJoseph Chen bank_size = gd->bd->bi_dram[i].size; 262305d8903SJoseph Chen if (sysmem_is_overlap(base, size, 263305d8903SJoseph Chen bank_base, bank_size)) { 2646e15146eSJoseph Chen req_overlap = true; 265305d8903SJoseph Chen break; 266305d8903SJoseph Chen } 267305d8903SJoseph Chen } 268305d8903SJoseph Chen 269efda1f1dSJoseph Chen /* 270efda1f1dSJoseph Chen * If this request region is out size of all available 271efda1f1dSJoseph Chen * region, ignore and return success. 272efda1f1dSJoseph Chen */ 273305d8903SJoseph Chen if (!req_overlap) 2746e15146eSJoseph Chen return (void *)base; 2756e15146eSJoseph Chen } 276efda1f1dSJoseph Chen 277efda1f1dSJoseph Chen /* Find name, id and attr by outer mem_name */ 2786e15146eSJoseph Chen name = sysmem_alias2name(mem_name, (int *)&id); 2796e15146eSJoseph Chen attr = mem_attr[id]; 280a90f2861SJoseph Chen if (!attr.name) 281a90f2861SJoseph Chen attr.name = strdup(name); 2826e15146eSJoseph Chen } else if (id > MEMBLK_ID_UNK && id < MEMBLK_ID_MAX) { 2836e15146eSJoseph Chen attr = mem_attr[id]; 2846e15146eSJoseph Chen name = attr.name; 285f6e15301SJoseph Chen 286f6e15301SJoseph Chen /* 287f6e15301SJoseph Chen * Fixup base and place right after U-Boot stack, adding a lot 288f6e15301SJoseph Chen * of space(4KB) maybe safer. 289f6e15301SJoseph Chen */ 290f6e15301SJoseph Chen if ((id == MEMBLK_ID_AVB_ANDROID) && 291598774ecSJoseph Chen (base == SYSMEM_ALLOC_ANYWHERE)) { 292f6e15301SJoseph Chen base = gd->start_addr_sp - 293f6e15301SJoseph Chen CONFIG_SYS_STACK_SIZE - size - 0x1000; 294598774ecSJoseph Chen /* 295598774ecSJoseph Chen * So far, we use M_ATTR_PEEK for uncompress kernel alloc, and 296598774ecSJoseph Chen * for ARMv8 enabling AArch32 mode, the ATF is still AArch64 297598774ecSJoseph Chen * and ocuppies 0~1MB and shmem 1~2M. So let's ignore the region 298598774ecSJoseph Chen * which overlap with them. 299598774ecSJoseph Chen */ 300598774ecSJoseph Chen } else if (attr.flags & M_ATTR_PEEK) { 301598774ecSJoseph Chen if (base <= gd->bd->bi_dram[0].start) 302598774ecSJoseph Chen base = gd->bd->bi_dram[0].start; 303598774ecSJoseph Chen } 3046e15146eSJoseph Chen } else { 3056e15146eSJoseph Chen SYSMEM_E("Unsupport memblk id %d for alloc sysmem\n", id); 306efda1f1dSJoseph Chen goto out; 3076e15146eSJoseph Chen } 3086e15146eSJoseph Chen 3096e15146eSJoseph Chen if (!size) { 3106e15146eSJoseph Chen SYSMEM_E("\"%s\" size is 0 for alloc sysmem\n", name); 311efda1f1dSJoseph Chen goto out; 312ffa8f8b7SJoseph Chen } 313ffa8f8b7SJoseph Chen 314556bbbe4SJoseph Chen /* 315556bbbe4SJoseph Chen * Some modules use "sysmem_alloc()" to alloc region for storage 316556bbbe4SJoseph Chen * read/write buffer, it should be aligned to cacheline size. eg: AVB. 317556bbbe4SJoseph Chen * 318556bbbe4SJoseph Chen * Aligned down to cacheline size if not aligned, otherwise the tail 319556bbbe4SJoseph Chen * of region maybe overflow. 320556bbbe4SJoseph Chen */ 321556bbbe4SJoseph Chen if (attr.flags & M_ATTR_CACHELINE_ALIGN && 322556bbbe4SJoseph Chen !IS_ALIGNED(base, ARCH_DMA_MINALIGN)) { 323556bbbe4SJoseph Chen base = ALIGN(base, ARCH_DMA_MINALIGN); 324556bbbe4SJoseph Chen base -= ARCH_DMA_MINALIGN; 325556bbbe4SJoseph Chen } 326556bbbe4SJoseph Chen 327727ebf6dSJoseph Chen if (!IS_ALIGNED(base, 4)) { 3286e15146eSJoseph Chen SYSMEM_E("\"%s\" base=0x%08lx is not 4-byte aligned\n", 3296e15146eSJoseph Chen name, (ulong)base); 330efda1f1dSJoseph Chen goto out; 331727ebf6dSJoseph Chen } 332727ebf6dSJoseph Chen 333727ebf6dSJoseph Chen /* Must be 4-byte aligned */ 334727ebf6dSJoseph Chen size = ALIGN(size, 4); 335727ebf6dSJoseph Chen 3366e15146eSJoseph Chen SYSMEM_D("Enter alloc: \"%s\" 0x%08lx - 0x%08lx\n", 3376e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size)); 3386e15146eSJoseph Chen 339ffa8f8b7SJoseph Chen /* Already allocated ? */ 340ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 3416e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 3426e15146eSJoseph Chen SYSMEM_D("Has allcated: %s, 0x%08lx - 0x%08lx\n", 3436e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 3446e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 3456e15146eSJoseph Chen if (!strcmp(mem->attr.name, name)) { 346efda1f1dSJoseph Chen /* Allow double alloc for same but smaller region */ 3472cb995bcSJoseph Chen if (mem->base <= base && mem->size >= size) 3482cb995bcSJoseph Chen return (void *)base; 3492cb995bcSJoseph Chen 350ffa8f8b7SJoseph Chen SYSMEM_E("Failed to double alloc for existence \"%s\"\n", name); 351efda1f1dSJoseph Chen goto out; 3526e15146eSJoseph Chen } else if (sysmem_is_overlap(mem->base, mem->size, base, size)) { 353efda1f1dSJoseph Chen /* 354efda1f1dSJoseph Chen * If this new alloc region expects overlap and the old 355efda1f1dSJoseph Chen * region is also allowed to be overlap, just do reserve. 356efda1f1dSJoseph Chen */ 3576e15146eSJoseph Chen if (req_overlap && mem->attr.flags & M_ATTR_OVERLAP) { 3586e15146eSJoseph Chen if (lmb_reserve(&sysmem->lmb, base, size)) 3596e15146eSJoseph Chen SYSMEM_E("Failed to overlap alloc \"%s\" " 3606e15146eSJoseph Chen "at 0x%08lx - 0x%08lx\n", 3616e15146eSJoseph Chen name, (ulong)base, 3626e15146eSJoseph Chen (ulong)(base + size)); 3636e15146eSJoseph Chen return (void *)base; 3646e15146eSJoseph Chen } 3656e15146eSJoseph Chen 3666e15146eSJoseph Chen SYSMEM_E("\"%s\" (0x%08lx - 0x%08lx) alloc is " 3676e15146eSJoseph Chen "overlap with existence \"%s\" (0x%08lx - " 3686e15146eSJoseph Chen "0x%08lx)\n", 3696e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size), 3706e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 3716e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 372efda1f1dSJoseph Chen goto out; 373ffa8f8b7SJoseph Chen } 374ffa8f8b7SJoseph Chen } 375ffa8f8b7SJoseph Chen 3766e15146eSJoseph Chen /* Add overflow check magic ? */ 3776e15146eSJoseph Chen if (attr.flags & M_ATTR_OFC) 378ffa8f8b7SJoseph Chen alloc_size = size + sizeof(*check); 3796e15146eSJoseph Chen else 3806e15146eSJoseph Chen alloc_size = size; 3816e15146eSJoseph Chen 3826e15146eSJoseph Chen /* Alloc anywhere ? */ 383ffa8f8b7SJoseph Chen if (base == SYSMEM_ALLOC_ANYWHERE) 384598774ecSJoseph Chen alloc_base = LMB_ALLOC_ANYWHERE; 385ffa8f8b7SJoseph Chen else 386ffa8f8b7SJoseph Chen alloc_base = base + alloc_size; /* LMB is align down alloc mechanism */ 387ffa8f8b7SJoseph Chen 388ffa8f8b7SJoseph Chen paddr = lmb_alloc_base(&sysmem->lmb, alloc_size, align, alloc_base); 389ffa8f8b7SJoseph Chen if (paddr) { 390ffa8f8b7SJoseph Chen if ((paddr == base) || (base == SYSMEM_ALLOC_ANYWHERE)) { 3916e15146eSJoseph Chen mem = malloc(sizeof(*mem)); 3926e15146eSJoseph Chen if (!mem) { 393ffa8f8b7SJoseph Chen SYSMEM_E("No memory for \"%s\" alloc sysmem\n", name); 394efda1f1dSJoseph Chen goto out; 395ffa8f8b7SJoseph Chen } 396ffa8f8b7SJoseph Chen 3976e15146eSJoseph Chen mem->base = paddr; 3986e15146eSJoseph Chen mem->size = alloc_size; 3996e15146eSJoseph Chen mem->attr = attr; 400ffa8f8b7SJoseph Chen sysmem->allocated_cnt++; 4016e15146eSJoseph Chen list_add_tail(&mem->node, &sysmem->allocated_head); 402ffa8f8b7SJoseph Chen 403efda1f1dSJoseph Chen /* Add overflow check magic */ 4046e15146eSJoseph Chen if (mem->attr.flags & M_ATTR_OFC) { 4056e15146eSJoseph Chen check = (struct memcheck *)(paddr + size); 406ffa8f8b7SJoseph Chen check->magic = SYSMEM_MAGIC; 4076e15146eSJoseph Chen } else if (mem->attr.flags & M_ATTR_HOFC) { 4086e15146eSJoseph Chen check = (struct memcheck *)(paddr - sizeof(*check)); 4096e15146eSJoseph Chen check->magic = SYSMEM_MAGIC; 4106e15146eSJoseph Chen } 411ffa8f8b7SJoseph Chen } else { 4126e15146eSJoseph Chen SYSMEM_E("Failed to alloc \"%s\" expect at 0x%08lx - 0x%08lx " 4136e15146eSJoseph Chen "but at 0x%08lx - x%08lx\n", 4146e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size), 4156e15146eSJoseph Chen (ulong)paddr, (ulong)(paddr + size)); 416efda1f1dSJoseph Chen /* Free what we don't want allocated region */ 4173bee194fSJoseph Chen if (lmb_free(&sysmem->lmb, paddr, alloc_size) < 0) 4186e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\"\n", name); 4196e15146eSJoseph Chen 420efda1f1dSJoseph Chen goto out; 421ffa8f8b7SJoseph Chen } 422ffa8f8b7SJoseph Chen } else { 4236e15146eSJoseph Chen SYSMEM_E("Failed to alloc \"%s\" at 0x%08lx - 0x%08lx\n", 4246e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size)); 425661cbb0bSJoseph Chen goto out; 426ffa8f8b7SJoseph Chen } 427ffa8f8b7SJoseph Chen 4286e15146eSJoseph Chen SYSMEM_D("Exit alloc: \"%s\", paddr=0x%08lx, size=0x%08lx, align=0x%x, anywhere=%d\n", 429ffa8f8b7SJoseph Chen name, (ulong)paddr, (ulong)size, (u32)align, !base); 430ffa8f8b7SJoseph Chen 431ffa8f8b7SJoseph Chen return (void *)paddr; 432efda1f1dSJoseph Chen 433efda1f1dSJoseph Chen out: 434598774ecSJoseph Chen /* 435598774ecSJoseph Chen * Why: base + sizeof(ulong) ? 436598774ecSJoseph Chen * It's a not standard way to handle the case: the input base is 0. 437598774ecSJoseph Chen */ 438598774ecSJoseph Chen if (base == 0) 439598774ecSJoseph Chen base = base + sizeof(ulong); 440598774ecSJoseph Chen 441efda1f1dSJoseph Chen return (attr.flags & M_ATTR_PEEK) ? (void *)base : NULL; 442ffa8f8b7SJoseph Chen } 443ffa8f8b7SJoseph Chen 444dcb404a6SJoseph Chen void *sysmem_alloc(enum memblk_id id, phys_size_t size) 445dcb404a6SJoseph Chen { 446dcb404a6SJoseph Chen void *paddr; 447dcb404a6SJoseph Chen 448dcb404a6SJoseph Chen paddr = sysmem_alloc_align_base(id, 449dcb404a6SJoseph Chen NULL, 450dcb404a6SJoseph Chen SYSMEM_ALLOC_ANYWHERE, 451dcb404a6SJoseph Chen size, 452dcb404a6SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 453dcb404a6SJoseph Chen if (!paddr) 454dcb404a6SJoseph Chen sysmem_dump(); 455dcb404a6SJoseph Chen 456dcb404a6SJoseph Chen return paddr; 457dcb404a6SJoseph Chen } 458dcb404a6SJoseph Chen 4596e15146eSJoseph Chen void *sysmem_alloc_base(enum memblk_id id, phys_addr_t base, phys_size_t size) 460ffa8f8b7SJoseph Chen { 4616e15146eSJoseph Chen void *paddr; 462ffa8f8b7SJoseph Chen 4636e15146eSJoseph Chen paddr = sysmem_alloc_align_base(id, 4646e15146eSJoseph Chen NULL, 465ffa8f8b7SJoseph Chen base, 466ffa8f8b7SJoseph Chen size, 467ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 4686e15146eSJoseph Chen if (!paddr) 4696e15146eSJoseph Chen sysmem_dump(); 4706e15146eSJoseph Chen 4716e15146eSJoseph Chen return paddr; 472ffa8f8b7SJoseph Chen } 473ffa8f8b7SJoseph Chen 4746e15146eSJoseph Chen void *sysmem_alloc_base_by_name(const char *name, 4756e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 476ffa8f8b7SJoseph Chen { 4776e15146eSJoseph Chen void *paddr; 4786e15146eSJoseph Chen 4796e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_BY_NAME, 4806e15146eSJoseph Chen name, 4816e15146eSJoseph Chen base, 482ffa8f8b7SJoseph Chen size, 483ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 4846e15146eSJoseph Chen if (!paddr) 4856e15146eSJoseph Chen sysmem_dump(); 4866e15146eSJoseph Chen 4876e15146eSJoseph Chen return paddr; 4886e15146eSJoseph Chen } 4896e15146eSJoseph Chen 4906e15146eSJoseph Chen void *sysmem_fdt_reserve_alloc_base(const char *name, 4916e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 4926e15146eSJoseph Chen { 4936e15146eSJoseph Chen void *paddr; 4946e15146eSJoseph Chen 4956e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_FDT_RESV, 4966e15146eSJoseph Chen name, 4976e15146eSJoseph Chen base, 4986e15146eSJoseph Chen size, 4996e15146eSJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 5006e15146eSJoseph Chen if (!paddr) 5016e15146eSJoseph Chen sysmem_dump(); 5026e15146eSJoseph Chen 5036e15146eSJoseph Chen return paddr; 504ffa8f8b7SJoseph Chen } 505ffa8f8b7SJoseph Chen 5063bee194fSJoseph Chen bool sysmem_can_alloc(phys_size_t base, phys_size_t size) 5073bee194fSJoseph Chen { 5083bee194fSJoseph Chen struct sysmem *sysmem = &plat_sysmem; 5093bee194fSJoseph Chen phys_addr_t alloc_base; 5103bee194fSJoseph Chen phys_addr_t paddr; 5113bee194fSJoseph Chen int ret; 5123bee194fSJoseph Chen 5133bee194fSJoseph Chen if (!sysmem_has_init()) 5143bee194fSJoseph Chen return false; 5153bee194fSJoseph Chen 5163bee194fSJoseph Chen /* LMB is align down alloc mechanism */ 5173bee194fSJoseph Chen alloc_base = base + size; 5183bee194fSJoseph Chen paddr = __lmb_alloc_base(&sysmem->lmb, 5193bee194fSJoseph Chen size, 5203bee194fSJoseph Chen SYSMEM_ALLOC_NO_ALIGN, 5213bee194fSJoseph Chen alloc_base); 5223bee194fSJoseph Chen if (paddr) { 5233bee194fSJoseph Chen /* If free failed, return false */ 5243bee194fSJoseph Chen ret = lmb_free(&sysmem->lmb, base, size); 5253bee194fSJoseph Chen if (ret < 0) { 5263bee194fSJoseph Chen SYSMEM_E("Can't free at 0x%08lx - 0x%08lx, ret=%d\n", 5273bee194fSJoseph Chen (ulong)base, (ulong)(base + size), ret); 5283bee194fSJoseph Chen return false; 5293bee194fSJoseph Chen } 5303bee194fSJoseph Chen } else { 5313bee194fSJoseph Chen SYSMEM_D("Can't alloc at 0x%08lx - 0x%08lx\n", 5323bee194fSJoseph Chen (ulong)base, (ulong)(base + size)); 5333bee194fSJoseph Chen } 5343bee194fSJoseph Chen 5353bee194fSJoseph Chen return (paddr == base) ? true : false; 5363bee194fSJoseph Chen } 5373bee194fSJoseph Chen 538ffa8f8b7SJoseph Chen int sysmem_free(phys_addr_t base) 539ffa8f8b7SJoseph Chen { 540ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 5416e15146eSJoseph Chen struct memblock *mem; 542ffa8f8b7SJoseph Chen struct list_head *node; 5436e15146eSJoseph Chen int ret, found = 0; 544ffa8f8b7SJoseph Chen 545ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 546ffa8f8b7SJoseph Chen return -ENOSYS; 547ffa8f8b7SJoseph Chen 548ffa8f8b7SJoseph Chen /* Find existence */ 549ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 5506e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 5516e15146eSJoseph Chen if (mem->base == base) { 552ffa8f8b7SJoseph Chen found = 1; 553ffa8f8b7SJoseph Chen break; 554ffa8f8b7SJoseph Chen } 555ffa8f8b7SJoseph Chen } 556ffa8f8b7SJoseph Chen 557ffa8f8b7SJoseph Chen if (!found) { 5586e15146eSJoseph Chen SYSMEM_E("Failed to free no allocated sysmem at 0x%08lx\n", 5596e15146eSJoseph Chen (ulong)base); 560ffa8f8b7SJoseph Chen return -EINVAL; 561ffa8f8b7SJoseph Chen } 562ffa8f8b7SJoseph Chen 5636e15146eSJoseph Chen ret = lmb_free(&sysmem->lmb, mem->base, mem->size); 564ffa8f8b7SJoseph Chen if (ret >= 0) { 5656e15146eSJoseph Chen SYSMEM_D("Free: \"%s\" 0x%08lx - 0x%08lx\n", 5666e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 5676e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 568ffa8f8b7SJoseph Chen sysmem->allocated_cnt--; 5696e15146eSJoseph Chen list_del(&mem->node); 5706e15146eSJoseph Chen free(mem); 571ffa8f8b7SJoseph Chen } else { 5726e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\" at 0x%08lx\n", 5736e15146eSJoseph Chen mem->attr.name, (ulong)base); 574ffa8f8b7SJoseph Chen } 575ffa8f8b7SJoseph Chen 576ffa8f8b7SJoseph Chen return (ret >= 0) ? 0 : ret; 577ffa8f8b7SJoseph Chen } 578ffa8f8b7SJoseph Chen 5796e15146eSJoseph Chen int sysmem_initr(void) 5806e15146eSJoseph Chen { 5816e15146eSJoseph Chen return sysmem_init(); 5826e15146eSJoseph Chen } 5836e15146eSJoseph Chen 584ffa8f8b7SJoseph Chen int sysmem_init(void) 585ffa8f8b7SJoseph Chen { 586ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 587ffa8f8b7SJoseph Chen phys_addr_t mem_start; 588ffa8f8b7SJoseph Chen phys_size_t mem_size; 589ffa8f8b7SJoseph Chen int ret; 590ffa8f8b7SJoseph Chen 591ffa8f8b7SJoseph Chen lmb_init(&sysmem->lmb); 592ffa8f8b7SJoseph Chen INIT_LIST_HEAD(&sysmem->allocated_head); 593ffa8f8b7SJoseph Chen sysmem->allocated_cnt = 0; 5946e15146eSJoseph Chen if (gd->flags & GD_FLG_RELOC) { 5956e15146eSJoseph Chen sysmem->has_initr = true; 5966e15146eSJoseph Chen } else { 5976e15146eSJoseph Chen SYSMEM_I("init\n"); 5986e15146eSJoseph Chen sysmem->has_initf = true; 5996e15146eSJoseph Chen } 600ffa8f8b7SJoseph Chen 601ffa8f8b7SJoseph Chen /* Add all available system memory */ 602ffa8f8b7SJoseph Chen #ifdef CONFIG_NR_DRAM_BANKS 603ffa8f8b7SJoseph Chen int i; 604ffa8f8b7SJoseph Chen 605ffa8f8b7SJoseph Chen for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 6066e15146eSJoseph Chen if (!gd->bd->bi_dram[i].size) 6076e15146eSJoseph Chen continue; 6086e15146eSJoseph Chen 609ffa8f8b7SJoseph Chen ret = sysmem_add(gd->bd->bi_dram[i].start, 610ffa8f8b7SJoseph Chen gd->bd->bi_dram[i].size); 611ffa8f8b7SJoseph Chen if (ret) { 612ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bi_dram[%d]\n", i); 6136e15146eSJoseph Chen goto fail; 614ffa8f8b7SJoseph Chen } 615ffa8f8b7SJoseph Chen } 616ffa8f8b7SJoseph Chen #else 617ffa8f8b7SJoseph Chen mem_start = env_get_bootm_low(); 618ffa8f8b7SJoseph Chen mem_size = env_get_bootm_size(); 619ffa8f8b7SJoseph Chen ret = sysmem_add(mem_start, mem_size); 620ffa8f8b7SJoseph Chen if (ret) { 621ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bootm_low/size\n"); 6226e15146eSJoseph Chen goto fail; 623ffa8f8b7SJoseph Chen } 624ffa8f8b7SJoseph Chen #endif 625ffa8f8b7SJoseph Chen /* Reserved for board */ 626ffa8f8b7SJoseph Chen ret = board_sysmem_reserve(sysmem); 627ffa8f8b7SJoseph Chen if (ret) { 628ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for board\n"); 6296e15146eSJoseph Chen goto fail; 630ffa8f8b7SJoseph Chen } 631ffa8f8b7SJoseph Chen 6326e15146eSJoseph Chen /* Reserved for U-boot framework: 'reserve_xxx()' */ 6336e15146eSJoseph Chen mem_start = gd->start_addr_sp; 634ffa8f8b7SJoseph Chen mem_size = gd->ram_top - mem_start; 6356e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_UBOOT, mem_start, mem_size)) { 636ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for U-Boot framework\n"); 6376e15146eSJoseph Chen ret = -ENOMEM; 6386e15146eSJoseph Chen goto fail; 639ffa8f8b7SJoseph Chen } 640ffa8f8b7SJoseph Chen 6416e15146eSJoseph Chen /* Reserved for U-Boot stack */ 6426e15146eSJoseph Chen mem_start = gd->start_addr_sp - CONFIG_SYS_STACK_SIZE; 6436e15146eSJoseph Chen mem_size = CONFIG_SYS_STACK_SIZE; 6446e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_STACK, mem_start, mem_size)) { 6456e15146eSJoseph Chen SYSMEM_E("Failed to reserve sysmem for stack\n"); 6466e15146eSJoseph Chen ret = -ENOMEM; 6476e15146eSJoseph Chen goto fail; 6486e15146eSJoseph Chen } 649ffa8f8b7SJoseph Chen 650ffa8f8b7SJoseph Chen return 0; 6516e15146eSJoseph Chen 6526e15146eSJoseph Chen fail: 6536e15146eSJoseph Chen if (ret && !(gd->flags & GD_FLG_RELOC)) { 6546e15146eSJoseph Chen sysmem_dump(); 6556e15146eSJoseph Chen SYSMEM_W("Maybe malloc size %d MiB is too large?\n\n", 6566e15146eSJoseph Chen SIZE_MB(CONFIG_SYS_MALLOC_LEN)); 6576e15146eSJoseph Chen } 6586e15146eSJoseph Chen 6596e15146eSJoseph Chen return ret; 660ffa8f8b7SJoseph Chen } 661ffa8f8b7SJoseph Chen 662ffa8f8b7SJoseph Chen __weak int board_sysmem_reserve(struct sysmem *sysmem) 663ffa8f8b7SJoseph Chen { 664ffa8f8b7SJoseph Chen /* please define platform specific board_sysmem_reserve() */ 665ffa8f8b7SJoseph Chen return 0; 666ffa8f8b7SJoseph Chen } 667ffa8f8b7SJoseph Chen 6686e15146eSJoseph Chen static int do_dump_sysmem(cmd_tbl_t *cmdtp, int flag, 6696e15146eSJoseph Chen int argc, char *const argv[]) 670ffa8f8b7SJoseph Chen { 6716e15146eSJoseph Chen sysmem_dump(); 672ffa8f8b7SJoseph Chen return 0; 673ffa8f8b7SJoseph Chen } 6746e15146eSJoseph Chen 6756e15146eSJoseph Chen U_BOOT_CMD( 6766e15146eSJoseph Chen dump_sysmem, 1, 1, do_dump_sysmem, 6776e15146eSJoseph Chen "Dump sysmem layout", 6786e15146eSJoseph Chen "" 6796e15146eSJoseph Chen ); 680