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