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 1266e15146eSJoseph Chen static inline int sysmem_is_overlap(phys_addr_t base1, phys_size_t size1, 127ffa8f8b7SJoseph Chen phys_addr_t base2, phys_size_t size2) 128ffa8f8b7SJoseph Chen { 129ffa8f8b7SJoseph Chen return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); 130ffa8f8b7SJoseph Chen } 131ffa8f8b7SJoseph Chen 1326e15146eSJoseph Chen static int sysmem_add(phys_addr_t base, phys_size_t size) 133ffa8f8b7SJoseph Chen { 134ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 135ffa8f8b7SJoseph Chen int ret; 136ffa8f8b7SJoseph Chen 1376e15146eSJoseph Chen if (!size) 1386e15146eSJoseph Chen return -EINVAL; 139ffa8f8b7SJoseph Chen 140ffa8f8b7SJoseph Chen ret = lmb_add(&sysmem->lmb, base, size); 141ffa8f8b7SJoseph Chen if (ret < 0) 1426e15146eSJoseph Chen SYSMEM_E("Failed to add sysmem at 0x%08lx for 0x%08lx size\n", 143ffa8f8b7SJoseph Chen (ulong)base, (ulong)size); 144ffa8f8b7SJoseph Chen 145ffa8f8b7SJoseph Chen return (ret >= 0) ? 0 : ret; 146ffa8f8b7SJoseph Chen } 147ffa8f8b7SJoseph Chen 1486e15146eSJoseph Chen static const char *sysmem_alias2name(const char *name, int *id) 149ffa8f8b7SJoseph Chen { 1506e15146eSJoseph Chen const char *alias; 1516e15146eSJoseph Chen int n, i, j; 1526e15146eSJoseph Chen int match = 0; 153ffa8f8b7SJoseph Chen 1546e15146eSJoseph Chen for (i = 0; i < MEMBLK_ID_MAX; i++) { 1556e15146eSJoseph Chen /* Pirmary name */ 1566e15146eSJoseph Chen if (mem_attr[i].name && !strcasecmp(mem_attr[i].name, name)) { 1576e15146eSJoseph Chen match = 1; 1586e15146eSJoseph Chen goto finish; 159ffa8f8b7SJoseph Chen } 160ffa8f8b7SJoseph Chen 1616e15146eSJoseph Chen /* Alias name */ 1626e15146eSJoseph Chen alias = mem_attr[i].alias[0]; 1636e15146eSJoseph Chen if (!alias) 1646e15146eSJoseph Chen continue; 1656e15146eSJoseph Chen 1666e15146eSJoseph Chen n = ARRAY_SIZE(mem_attr[i].alias); 1676e15146eSJoseph Chen for (j = 0; j < n; j++, alias++) { 1686e15146eSJoseph Chen if (alias && !strcasecmp(alias, name)) { 1696e15146eSJoseph Chen match = 1; 1706e15146eSJoseph Chen goto finish; 1716e15146eSJoseph Chen } 172ffa8f8b7SJoseph Chen } 173ffa8f8b7SJoseph Chen } 174ffa8f8b7SJoseph Chen 1756e15146eSJoseph Chen finish: 1766e15146eSJoseph Chen if (match) { 1776e15146eSJoseph Chen *id = i; 1786e15146eSJoseph Chen return mem_attr[i].name; 179ffa8f8b7SJoseph Chen } 180ffa8f8b7SJoseph Chen 1816e15146eSJoseph Chen return name; 182ffa8f8b7SJoseph Chen } 183ffa8f8b7SJoseph Chen 1846e15146eSJoseph Chen static void *sysmem_alloc_align_base(enum memblk_id id, 1856e15146eSJoseph Chen const char *mem_name, 186ffa8f8b7SJoseph Chen phys_addr_t base, 187ffa8f8b7SJoseph Chen phys_size_t size, 188ffa8f8b7SJoseph Chen ulong align) 189ffa8f8b7SJoseph Chen { 190ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 1916e15146eSJoseph Chen struct memblk_attr attr; 1926e15146eSJoseph Chen struct memblock *mem; 1936e15146eSJoseph Chen struct memcheck *check; 194ffa8f8b7SJoseph Chen struct list_head *node; 1956e15146eSJoseph Chen const char *name; 196ffa8f8b7SJoseph Chen phys_addr_t paddr; 197ffa8f8b7SJoseph Chen phys_addr_t alloc_base; 198ffa8f8b7SJoseph Chen phys_size_t alloc_size; 199305d8903SJoseph Chen phys_addr_t bank_base; 200305d8903SJoseph Chen phys_size_t bank_size; 201305d8903SJoseph Chen bool req_overlap = false; /* Only for kernel reserved-memory */ 202305d8903SJoseph Chen int i; 203ffa8f8b7SJoseph Chen 204ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 205efda1f1dSJoseph Chen goto out; 206ffa8f8b7SJoseph Chen 2076e15146eSJoseph Chen if (id == MEMBLK_ID_BY_NAME || id == MEMBLK_ID_FDT_RESV) { 2086e15146eSJoseph Chen if (!mem_name) { 209ffa8f8b7SJoseph Chen SYSMEM_E("NULL name for alloc sysmem\n"); 210efda1f1dSJoseph Chen goto out; 2116e15146eSJoseph Chen } else if (id == MEMBLK_ID_FDT_RESV) { 212efda1f1dSJoseph Chen 213efda1f1dSJoseph Chen /* 214efda1f1dSJoseph Chen * Allow fdt reserved memory to overlap with the region 215efda1f1dSJoseph Chen * only used in U-Boot, like: stack, fastboot, u-boot... 216efda1f1dSJoseph Chen * these regions are marked as M_ATTR_OVERLAP in flags. 217efda1f1dSJoseph Chen * 218efda1f1dSJoseph Chen * Here we check whether it overlaps with others, if 219efda1f1dSJoseph Chen * so, set req_overlap as true. 220efda1f1dSJoseph Chen */ 221305d8903SJoseph Chen for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 222305d8903SJoseph Chen if (!gd->bd->bi_dram[i].size) 223305d8903SJoseph Chen continue; 224305d8903SJoseph Chen 225305d8903SJoseph Chen bank_base = gd->bd->bi_dram[i].start; 226305d8903SJoseph Chen bank_size = gd->bd->bi_dram[i].size; 227305d8903SJoseph Chen if (sysmem_is_overlap(base, size, 228305d8903SJoseph Chen bank_base, bank_size)) { 2296e15146eSJoseph Chen req_overlap = true; 230305d8903SJoseph Chen break; 231305d8903SJoseph Chen } 232305d8903SJoseph Chen } 233305d8903SJoseph Chen 234efda1f1dSJoseph Chen /* 235efda1f1dSJoseph Chen * If this request region is out size of all available 236efda1f1dSJoseph Chen * region, ignore and return success. 237efda1f1dSJoseph Chen */ 238305d8903SJoseph Chen if (!req_overlap) 2396e15146eSJoseph Chen return (void *)base; 2406e15146eSJoseph Chen } 241efda1f1dSJoseph Chen 242efda1f1dSJoseph Chen /* Find name, id and attr by outer mem_name */ 2436e15146eSJoseph Chen name = sysmem_alias2name(mem_name, (int *)&id); 2446e15146eSJoseph Chen attr = mem_attr[id]; 245a90f2861SJoseph Chen if (!attr.name) 246a90f2861SJoseph Chen attr.name = strdup(name); 2476e15146eSJoseph Chen } else if (id > MEMBLK_ID_UNK && id < MEMBLK_ID_MAX) { 2486e15146eSJoseph Chen attr = mem_attr[id]; 2496e15146eSJoseph Chen name = attr.name; 250f6e15301SJoseph Chen 251f6e15301SJoseph Chen /* 252f6e15301SJoseph Chen * Fixup base and place right after U-Boot stack, adding a lot 253f6e15301SJoseph Chen * of space(4KB) maybe safer. 254f6e15301SJoseph Chen */ 255f6e15301SJoseph Chen if ((id == MEMBLK_ID_AVB_ANDROID) && 256598774ecSJoseph Chen (base == SYSMEM_ALLOC_ANYWHERE)) { 257f6e15301SJoseph Chen base = gd->start_addr_sp - 258f6e15301SJoseph Chen CONFIG_SYS_STACK_SIZE - size - 0x1000; 259598774ecSJoseph Chen /* 260598774ecSJoseph Chen * So far, we use M_ATTR_PEEK for uncompress kernel alloc, and 261598774ecSJoseph Chen * for ARMv8 enabling AArch32 mode, the ATF is still AArch64 262598774ecSJoseph Chen * and ocuppies 0~1MB and shmem 1~2M. So let's ignore the region 263598774ecSJoseph Chen * which overlap with them. 264598774ecSJoseph Chen */ 265598774ecSJoseph Chen } else if (attr.flags & M_ATTR_PEEK) { 266598774ecSJoseph Chen if (base <= gd->bd->bi_dram[0].start) 267598774ecSJoseph Chen base = gd->bd->bi_dram[0].start; 268598774ecSJoseph Chen } 2696e15146eSJoseph Chen } else { 2706e15146eSJoseph Chen SYSMEM_E("Unsupport memblk id %d for alloc sysmem\n", id); 271efda1f1dSJoseph Chen goto out; 2726e15146eSJoseph Chen } 2736e15146eSJoseph Chen 2746e15146eSJoseph Chen if (!size) { 2756e15146eSJoseph Chen SYSMEM_E("\"%s\" size is 0 for alloc sysmem\n", name); 276efda1f1dSJoseph Chen goto out; 277ffa8f8b7SJoseph Chen } 278ffa8f8b7SJoseph Chen 279*556bbbe4SJoseph Chen /* 280*556bbbe4SJoseph Chen * Some modules use "sysmem_alloc()" to alloc region for storage 281*556bbbe4SJoseph Chen * read/write buffer, it should be aligned to cacheline size. eg: AVB. 282*556bbbe4SJoseph Chen * 283*556bbbe4SJoseph Chen * Aligned down to cacheline size if not aligned, otherwise the tail 284*556bbbe4SJoseph Chen * of region maybe overflow. 285*556bbbe4SJoseph Chen */ 286*556bbbe4SJoseph Chen if (attr.flags & M_ATTR_CACHELINE_ALIGN && 287*556bbbe4SJoseph Chen !IS_ALIGNED(base, ARCH_DMA_MINALIGN)) { 288*556bbbe4SJoseph Chen base = ALIGN(base, ARCH_DMA_MINALIGN); 289*556bbbe4SJoseph Chen base -= ARCH_DMA_MINALIGN; 290*556bbbe4SJoseph Chen } 291*556bbbe4SJoseph Chen 292727ebf6dSJoseph Chen if (!IS_ALIGNED(base, 4)) { 2936e15146eSJoseph Chen SYSMEM_E("\"%s\" base=0x%08lx is not 4-byte aligned\n", 2946e15146eSJoseph Chen name, (ulong)base); 295efda1f1dSJoseph Chen goto out; 296727ebf6dSJoseph Chen } 297727ebf6dSJoseph Chen 298727ebf6dSJoseph Chen /* Must be 4-byte aligned */ 299727ebf6dSJoseph Chen size = ALIGN(size, 4); 300727ebf6dSJoseph Chen 3016e15146eSJoseph Chen SYSMEM_D("Enter alloc: \"%s\" 0x%08lx - 0x%08lx\n", 3026e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size)); 3036e15146eSJoseph Chen 304ffa8f8b7SJoseph Chen /* Already allocated ? */ 305ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 3066e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 3076e15146eSJoseph Chen SYSMEM_D("Has allcated: %s, 0x%08lx - 0x%08lx\n", 3086e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 3096e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 3106e15146eSJoseph Chen if (!strcmp(mem->attr.name, name)) { 311efda1f1dSJoseph Chen /* Allow double alloc for same but smaller region */ 3122cb995bcSJoseph Chen if (mem->base <= base && mem->size >= size) 3132cb995bcSJoseph Chen return (void *)base; 3142cb995bcSJoseph Chen 315ffa8f8b7SJoseph Chen SYSMEM_E("Failed to double alloc for existence \"%s\"\n", name); 316efda1f1dSJoseph Chen goto out; 3176e15146eSJoseph Chen } else if (sysmem_is_overlap(mem->base, mem->size, base, size)) { 318efda1f1dSJoseph Chen /* 319efda1f1dSJoseph Chen * If this new alloc region expects overlap and the old 320efda1f1dSJoseph Chen * region is also allowed to be overlap, just do reserve. 321efda1f1dSJoseph Chen */ 3226e15146eSJoseph Chen if (req_overlap && mem->attr.flags & M_ATTR_OVERLAP) { 3236e15146eSJoseph Chen if (lmb_reserve(&sysmem->lmb, base, size)) 3246e15146eSJoseph Chen SYSMEM_E("Failed to overlap alloc \"%s\" " 3256e15146eSJoseph Chen "at 0x%08lx - 0x%08lx\n", 3266e15146eSJoseph Chen name, (ulong)base, 3276e15146eSJoseph Chen (ulong)(base + size)); 3286e15146eSJoseph Chen return (void *)base; 3296e15146eSJoseph Chen } 3306e15146eSJoseph Chen 3316e15146eSJoseph Chen SYSMEM_E("\"%s\" (0x%08lx - 0x%08lx) alloc is " 3326e15146eSJoseph Chen "overlap with existence \"%s\" (0x%08lx - " 3336e15146eSJoseph Chen "0x%08lx)\n", 3346e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size), 3356e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 3366e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 337efda1f1dSJoseph Chen goto out; 338ffa8f8b7SJoseph Chen } 339ffa8f8b7SJoseph Chen } 340ffa8f8b7SJoseph Chen 3416e15146eSJoseph Chen /* Add overflow check magic ? */ 3426e15146eSJoseph Chen if (attr.flags & M_ATTR_OFC) 343ffa8f8b7SJoseph Chen alloc_size = size + sizeof(*check); 3446e15146eSJoseph Chen else 3456e15146eSJoseph Chen alloc_size = size; 3466e15146eSJoseph Chen 3476e15146eSJoseph Chen /* Alloc anywhere ? */ 348ffa8f8b7SJoseph Chen if (base == SYSMEM_ALLOC_ANYWHERE) 349598774ecSJoseph Chen alloc_base = LMB_ALLOC_ANYWHERE; 350ffa8f8b7SJoseph Chen else 351ffa8f8b7SJoseph Chen alloc_base = base + alloc_size; /* LMB is align down alloc mechanism */ 352ffa8f8b7SJoseph Chen 353ffa8f8b7SJoseph Chen paddr = lmb_alloc_base(&sysmem->lmb, alloc_size, align, alloc_base); 354ffa8f8b7SJoseph Chen if (paddr) { 355ffa8f8b7SJoseph Chen if ((paddr == base) || (base == SYSMEM_ALLOC_ANYWHERE)) { 3566e15146eSJoseph Chen mem = malloc(sizeof(*mem)); 3576e15146eSJoseph Chen if (!mem) { 358ffa8f8b7SJoseph Chen SYSMEM_E("No memory for \"%s\" alloc sysmem\n", name); 359efda1f1dSJoseph Chen goto out; 360ffa8f8b7SJoseph Chen } 361ffa8f8b7SJoseph Chen 3626e15146eSJoseph Chen mem->base = paddr; 3636e15146eSJoseph Chen mem->size = alloc_size; 3646e15146eSJoseph Chen mem->attr = attr; 365ffa8f8b7SJoseph Chen sysmem->allocated_cnt++; 3666e15146eSJoseph Chen list_add_tail(&mem->node, &sysmem->allocated_head); 367ffa8f8b7SJoseph Chen 368efda1f1dSJoseph Chen /* Add overflow check magic */ 3696e15146eSJoseph Chen if (mem->attr.flags & M_ATTR_OFC) { 3706e15146eSJoseph Chen check = (struct memcheck *)(paddr + size); 371ffa8f8b7SJoseph Chen check->magic = SYSMEM_MAGIC; 3726e15146eSJoseph Chen } else if (mem->attr.flags & M_ATTR_HOFC) { 3736e15146eSJoseph Chen check = (struct memcheck *)(paddr - sizeof(*check)); 3746e15146eSJoseph Chen check->magic = SYSMEM_MAGIC; 3756e15146eSJoseph Chen } 376ffa8f8b7SJoseph Chen } else { 3776e15146eSJoseph Chen SYSMEM_E("Failed to alloc \"%s\" expect at 0x%08lx - 0x%08lx " 3786e15146eSJoseph Chen "but at 0x%08lx - x%08lx\n", 3796e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size), 3806e15146eSJoseph Chen (ulong)paddr, (ulong)(paddr + size)); 381efda1f1dSJoseph Chen /* Free what we don't want allocated region */ 3823bee194fSJoseph Chen if (lmb_free(&sysmem->lmb, paddr, alloc_size) < 0) 3836e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\"\n", name); 3846e15146eSJoseph Chen 385efda1f1dSJoseph Chen goto out; 386ffa8f8b7SJoseph Chen } 387ffa8f8b7SJoseph Chen } else { 3886e15146eSJoseph Chen SYSMEM_E("Failed to alloc \"%s\" at 0x%08lx - 0x%08lx\n", 3896e15146eSJoseph Chen name, (ulong)base, (ulong)(base + size)); 390661cbb0bSJoseph Chen goto out; 391ffa8f8b7SJoseph Chen } 392ffa8f8b7SJoseph Chen 3936e15146eSJoseph Chen SYSMEM_D("Exit alloc: \"%s\", paddr=0x%08lx, size=0x%08lx, align=0x%x, anywhere=%d\n", 394ffa8f8b7SJoseph Chen name, (ulong)paddr, (ulong)size, (u32)align, !base); 395ffa8f8b7SJoseph Chen 396ffa8f8b7SJoseph Chen return (void *)paddr; 397efda1f1dSJoseph Chen 398efda1f1dSJoseph Chen out: 399598774ecSJoseph Chen /* 400598774ecSJoseph Chen * Why: base + sizeof(ulong) ? 401598774ecSJoseph Chen * It's a not standard way to handle the case: the input base is 0. 402598774ecSJoseph Chen */ 403598774ecSJoseph Chen if (base == 0) 404598774ecSJoseph Chen base = base + sizeof(ulong); 405598774ecSJoseph Chen 406efda1f1dSJoseph Chen return (attr.flags & M_ATTR_PEEK) ? (void *)base : NULL; 407ffa8f8b7SJoseph Chen } 408ffa8f8b7SJoseph Chen 409dcb404a6SJoseph Chen void *sysmem_alloc(enum memblk_id id, phys_size_t size) 410dcb404a6SJoseph Chen { 411dcb404a6SJoseph Chen void *paddr; 412dcb404a6SJoseph Chen 413dcb404a6SJoseph Chen paddr = sysmem_alloc_align_base(id, 414dcb404a6SJoseph Chen NULL, 415dcb404a6SJoseph Chen SYSMEM_ALLOC_ANYWHERE, 416dcb404a6SJoseph Chen size, 417dcb404a6SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 418dcb404a6SJoseph Chen if (!paddr) 419dcb404a6SJoseph Chen sysmem_dump(); 420dcb404a6SJoseph Chen 421dcb404a6SJoseph Chen return paddr; 422dcb404a6SJoseph Chen } 423dcb404a6SJoseph Chen 4246e15146eSJoseph Chen void *sysmem_alloc_base(enum memblk_id id, phys_addr_t base, phys_size_t size) 425ffa8f8b7SJoseph Chen { 4266e15146eSJoseph Chen void *paddr; 427ffa8f8b7SJoseph Chen 4286e15146eSJoseph Chen paddr = sysmem_alloc_align_base(id, 4296e15146eSJoseph Chen NULL, 430ffa8f8b7SJoseph Chen base, 431ffa8f8b7SJoseph Chen size, 432ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 4336e15146eSJoseph Chen if (!paddr) 4346e15146eSJoseph Chen sysmem_dump(); 4356e15146eSJoseph Chen 4366e15146eSJoseph Chen return paddr; 437ffa8f8b7SJoseph Chen } 438ffa8f8b7SJoseph Chen 4396e15146eSJoseph Chen void *sysmem_alloc_base_by_name(const char *name, 4406e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 441ffa8f8b7SJoseph Chen { 4426e15146eSJoseph Chen void *paddr; 4436e15146eSJoseph Chen 4446e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_BY_NAME, 4456e15146eSJoseph Chen name, 4466e15146eSJoseph Chen base, 447ffa8f8b7SJoseph Chen size, 448ffa8f8b7SJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 4496e15146eSJoseph Chen if (!paddr) 4506e15146eSJoseph Chen sysmem_dump(); 4516e15146eSJoseph Chen 4526e15146eSJoseph Chen return paddr; 4536e15146eSJoseph Chen } 4546e15146eSJoseph Chen 4556e15146eSJoseph Chen void *sysmem_fdt_reserve_alloc_base(const char *name, 4566e15146eSJoseph Chen phys_addr_t base, phys_size_t size) 4576e15146eSJoseph Chen { 4586e15146eSJoseph Chen void *paddr; 4596e15146eSJoseph Chen 4606e15146eSJoseph Chen paddr = sysmem_alloc_align_base(MEMBLK_ID_FDT_RESV, 4616e15146eSJoseph Chen name, 4626e15146eSJoseph Chen base, 4636e15146eSJoseph Chen size, 4646e15146eSJoseph Chen SYSMEM_ALLOC_NO_ALIGN); 4656e15146eSJoseph Chen if (!paddr) 4666e15146eSJoseph Chen sysmem_dump(); 4676e15146eSJoseph Chen 4686e15146eSJoseph Chen return paddr; 469ffa8f8b7SJoseph Chen } 470ffa8f8b7SJoseph Chen 4713bee194fSJoseph Chen bool sysmem_can_alloc(phys_size_t base, phys_size_t size) 4723bee194fSJoseph Chen { 4733bee194fSJoseph Chen struct sysmem *sysmem = &plat_sysmem; 4743bee194fSJoseph Chen phys_addr_t alloc_base; 4753bee194fSJoseph Chen phys_addr_t paddr; 4763bee194fSJoseph Chen int ret; 4773bee194fSJoseph Chen 4783bee194fSJoseph Chen if (!sysmem_has_init()) 4793bee194fSJoseph Chen return false; 4803bee194fSJoseph Chen 4813bee194fSJoseph Chen /* LMB is align down alloc mechanism */ 4823bee194fSJoseph Chen alloc_base = base + size; 4833bee194fSJoseph Chen paddr = __lmb_alloc_base(&sysmem->lmb, 4843bee194fSJoseph Chen size, 4853bee194fSJoseph Chen SYSMEM_ALLOC_NO_ALIGN, 4863bee194fSJoseph Chen alloc_base); 4873bee194fSJoseph Chen if (paddr) { 4883bee194fSJoseph Chen /* If free failed, return false */ 4893bee194fSJoseph Chen ret = lmb_free(&sysmem->lmb, base, size); 4903bee194fSJoseph Chen if (ret < 0) { 4913bee194fSJoseph Chen SYSMEM_E("Can't free at 0x%08lx - 0x%08lx, ret=%d\n", 4923bee194fSJoseph Chen (ulong)base, (ulong)(base + size), ret); 4933bee194fSJoseph Chen return false; 4943bee194fSJoseph Chen } 4953bee194fSJoseph Chen } else { 4963bee194fSJoseph Chen SYSMEM_D("Can't alloc at 0x%08lx - 0x%08lx\n", 4973bee194fSJoseph Chen (ulong)base, (ulong)(base + size)); 4983bee194fSJoseph Chen } 4993bee194fSJoseph Chen 5003bee194fSJoseph Chen return (paddr == base) ? true : false; 5013bee194fSJoseph Chen } 5023bee194fSJoseph Chen 503ffa8f8b7SJoseph Chen int sysmem_free(phys_addr_t base) 504ffa8f8b7SJoseph Chen { 505ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 5066e15146eSJoseph Chen struct memblock *mem; 507ffa8f8b7SJoseph Chen struct list_head *node; 5086e15146eSJoseph Chen int ret, found = 0; 509ffa8f8b7SJoseph Chen 510ffa8f8b7SJoseph Chen if (!sysmem_has_init()) 511ffa8f8b7SJoseph Chen return -ENOSYS; 512ffa8f8b7SJoseph Chen 513ffa8f8b7SJoseph Chen /* Find existence */ 514ffa8f8b7SJoseph Chen list_for_each(node, &sysmem->allocated_head) { 5156e15146eSJoseph Chen mem = list_entry(node, struct memblock, node); 5166e15146eSJoseph Chen if (mem->base == base) { 517ffa8f8b7SJoseph Chen found = 1; 518ffa8f8b7SJoseph Chen break; 519ffa8f8b7SJoseph Chen } 520ffa8f8b7SJoseph Chen } 521ffa8f8b7SJoseph Chen 522ffa8f8b7SJoseph Chen if (!found) { 5236e15146eSJoseph Chen SYSMEM_E("Failed to free no allocated sysmem at 0x%08lx\n", 5246e15146eSJoseph Chen (ulong)base); 525ffa8f8b7SJoseph Chen return -EINVAL; 526ffa8f8b7SJoseph Chen } 527ffa8f8b7SJoseph Chen 5286e15146eSJoseph Chen ret = lmb_free(&sysmem->lmb, mem->base, mem->size); 529ffa8f8b7SJoseph Chen if (ret >= 0) { 5306e15146eSJoseph Chen SYSMEM_D("Free: \"%s\" 0x%08lx - 0x%08lx\n", 5316e15146eSJoseph Chen mem->attr.name, (ulong)mem->base, 5326e15146eSJoseph Chen (ulong)(mem->base + mem->size)); 533ffa8f8b7SJoseph Chen sysmem->allocated_cnt--; 5346e15146eSJoseph Chen list_del(&mem->node); 5356e15146eSJoseph Chen free(mem); 536ffa8f8b7SJoseph Chen } else { 5376e15146eSJoseph Chen SYSMEM_E("Failed to free \"%s\" at 0x%08lx\n", 5386e15146eSJoseph Chen mem->attr.name, (ulong)base); 539ffa8f8b7SJoseph Chen } 540ffa8f8b7SJoseph Chen 541ffa8f8b7SJoseph Chen return (ret >= 0) ? 0 : ret; 542ffa8f8b7SJoseph Chen } 543ffa8f8b7SJoseph Chen 5446e15146eSJoseph Chen int sysmem_initr(void) 5456e15146eSJoseph Chen { 5466e15146eSJoseph Chen return sysmem_init(); 5476e15146eSJoseph Chen } 5486e15146eSJoseph Chen 549ffa8f8b7SJoseph Chen int sysmem_init(void) 550ffa8f8b7SJoseph Chen { 551ffa8f8b7SJoseph Chen struct sysmem *sysmem = &plat_sysmem; 552ffa8f8b7SJoseph Chen phys_addr_t mem_start; 553ffa8f8b7SJoseph Chen phys_size_t mem_size; 554ffa8f8b7SJoseph Chen int ret; 555ffa8f8b7SJoseph Chen 556ffa8f8b7SJoseph Chen lmb_init(&sysmem->lmb); 557ffa8f8b7SJoseph Chen INIT_LIST_HEAD(&sysmem->allocated_head); 558ffa8f8b7SJoseph Chen sysmem->allocated_cnt = 0; 5596e15146eSJoseph Chen if (gd->flags & GD_FLG_RELOC) { 5606e15146eSJoseph Chen sysmem->has_initr = true; 5616e15146eSJoseph Chen } else { 5626e15146eSJoseph Chen SYSMEM_I("init\n"); 5636e15146eSJoseph Chen sysmem->has_initf = true; 5646e15146eSJoseph Chen } 565ffa8f8b7SJoseph Chen 566ffa8f8b7SJoseph Chen /* Add all available system memory */ 567ffa8f8b7SJoseph Chen #ifdef CONFIG_NR_DRAM_BANKS 568ffa8f8b7SJoseph Chen int i; 569ffa8f8b7SJoseph Chen 570ffa8f8b7SJoseph Chen for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 5716e15146eSJoseph Chen if (!gd->bd->bi_dram[i].size) 5726e15146eSJoseph Chen continue; 5736e15146eSJoseph Chen 574ffa8f8b7SJoseph Chen ret = sysmem_add(gd->bd->bi_dram[i].start, 575ffa8f8b7SJoseph Chen gd->bd->bi_dram[i].size); 576ffa8f8b7SJoseph Chen if (ret) { 577ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bi_dram[%d]\n", i); 5786e15146eSJoseph Chen goto fail; 579ffa8f8b7SJoseph Chen } 580ffa8f8b7SJoseph Chen } 581ffa8f8b7SJoseph Chen #else 582ffa8f8b7SJoseph Chen mem_start = env_get_bootm_low(); 583ffa8f8b7SJoseph Chen mem_size = env_get_bootm_size(); 584ffa8f8b7SJoseph Chen ret = sysmem_add(mem_start, mem_size); 585ffa8f8b7SJoseph Chen if (ret) { 586ffa8f8b7SJoseph Chen SYSMEM_E("Failed to add sysmem from bootm_low/size\n"); 5876e15146eSJoseph Chen goto fail; 588ffa8f8b7SJoseph Chen } 589ffa8f8b7SJoseph Chen #endif 590ffa8f8b7SJoseph Chen /* Reserved for board */ 591ffa8f8b7SJoseph Chen ret = board_sysmem_reserve(sysmem); 592ffa8f8b7SJoseph Chen if (ret) { 593ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for board\n"); 5946e15146eSJoseph Chen goto fail; 595ffa8f8b7SJoseph Chen } 596ffa8f8b7SJoseph Chen 5976e15146eSJoseph Chen /* Reserved for U-boot framework: 'reserve_xxx()' */ 5986e15146eSJoseph Chen mem_start = gd->start_addr_sp; 599ffa8f8b7SJoseph Chen mem_size = gd->ram_top - mem_start; 6006e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_UBOOT, mem_start, mem_size)) { 601ffa8f8b7SJoseph Chen SYSMEM_E("Failed to reserve sysmem for U-Boot framework\n"); 6026e15146eSJoseph Chen ret = -ENOMEM; 6036e15146eSJoseph Chen goto fail; 604ffa8f8b7SJoseph Chen } 605ffa8f8b7SJoseph Chen 6066e15146eSJoseph Chen /* Reserved for U-Boot stack */ 6076e15146eSJoseph Chen mem_start = gd->start_addr_sp - CONFIG_SYS_STACK_SIZE; 6086e15146eSJoseph Chen mem_size = CONFIG_SYS_STACK_SIZE; 6096e15146eSJoseph Chen if (!sysmem_alloc_base(MEMBLK_ID_STACK, mem_start, mem_size)) { 6106e15146eSJoseph Chen SYSMEM_E("Failed to reserve sysmem for stack\n"); 6116e15146eSJoseph Chen ret = -ENOMEM; 6126e15146eSJoseph Chen goto fail; 6136e15146eSJoseph Chen } 614ffa8f8b7SJoseph Chen 615ffa8f8b7SJoseph Chen return 0; 6166e15146eSJoseph Chen 6176e15146eSJoseph Chen fail: 6186e15146eSJoseph Chen if (ret && !(gd->flags & GD_FLG_RELOC)) { 6196e15146eSJoseph Chen sysmem_dump(); 6206e15146eSJoseph Chen SYSMEM_W("Maybe malloc size %d MiB is too large?\n\n", 6216e15146eSJoseph Chen SIZE_MB(CONFIG_SYS_MALLOC_LEN)); 6226e15146eSJoseph Chen } 6236e15146eSJoseph Chen 6246e15146eSJoseph Chen return ret; 625ffa8f8b7SJoseph Chen } 626ffa8f8b7SJoseph Chen 627ffa8f8b7SJoseph Chen __weak int board_sysmem_reserve(struct sysmem *sysmem) 628ffa8f8b7SJoseph Chen { 629ffa8f8b7SJoseph Chen /* please define platform specific board_sysmem_reserve() */ 630ffa8f8b7SJoseph Chen return 0; 631ffa8f8b7SJoseph Chen } 632ffa8f8b7SJoseph Chen 6336e15146eSJoseph Chen static int do_dump_sysmem(cmd_tbl_t *cmdtp, int flag, 6346e15146eSJoseph Chen int argc, char *const argv[]) 635ffa8f8b7SJoseph Chen { 6366e15146eSJoseph Chen sysmem_dump(); 637ffa8f8b7SJoseph Chen return 0; 638ffa8f8b7SJoseph Chen } 6396e15146eSJoseph Chen 6406e15146eSJoseph Chen U_BOOT_CMD( 6416e15146eSJoseph Chen dump_sysmem, 1, 1, do_dump_sysmem, 6426e15146eSJoseph Chen "Dump sysmem layout", 6436e15146eSJoseph Chen "" 6446e15146eSJoseph Chen ); 645