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_D("\"%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 if (!IS_ALIGNED(base, 4)) { 270 SYSMEM_E("\"%s\" base=0x%08lx is not 4-byte aligned\n", name, (ulong)base); 271 return NULL; 272 } 273 274 /* Must be 4-byte aligned */ 275 size = ALIGN(size, 4); 276 277 /* Already allocated ? */ 278 list_for_each(node, &sysmem->allocated_head) { 279 prop = list_entry(node, struct sysmem_property, node); 280 if (!strcmp(prop->name, name)) { 281 SYSMEM_E("Failed to double alloc for existence \"%s\"\n", name); 282 return NULL; 283 } else if (sysmem_is_overlap(prop->base, prop->size, base, size)) { 284 SYSMEM_E("\"%s\" (base=0x%08lx, size=0x%lx) alloc is " 285 "overlap with existence \"%s\" (base=0x%08lx, size=0x%lx)\n", 286 name, (ulong)base, (ulong)size, 287 prop->name, (ulong)prop->base, 288 (ulong)prop->size); 289 return NULL; 290 } 291 } 292 293 alloc_size = size + sizeof(*check); 294 if (base == SYSMEM_ALLOC_ANYWHERE) 295 alloc_base = base; 296 else 297 alloc_base = base + alloc_size; /* LMB is align down alloc mechanism */ 298 299 paddr = lmb_alloc_base(&sysmem->lmb, alloc_size, align, alloc_base); 300 if (paddr) { 301 if ((paddr == base) || (base == SYSMEM_ALLOC_ANYWHERE)) { 302 prop = malloc(sizeof(*prop)); 303 if (!prop) { 304 SYSMEM_E("No memory for \"%s\" alloc sysmem\n", name); 305 return NULL; 306 } 307 308 prop->name = name; 309 prop->base = paddr; 310 prop->size = alloc_size; 311 sysmem->allocated_cnt++; 312 313 check = (struct sysmem_check *)(paddr + size); 314 check->magic = SYSMEM_MAGIC; 315 316 list_add_tail(&prop->node, &sysmem->allocated_head); 317 } else { 318 SYSMEM_E("Failed to alloc \"%s\" at expect 0x%lx but " 319 "alloc at 0x%lx\n", 320 name, (ulong)base, (ulong)paddr); 321 return NULL; 322 } 323 } else { 324 SYSMEM_E("Failed to alloc \"%s\" at 0x%lx\n", name, (ulong)base); 325 } 326 327 SYSMEM_D("Alloc: \"%s\", paddr=0x%lx, size=0x%lx, align=0x%x, anywhere=%d\n", 328 name, (ulong)paddr, (ulong)size, (u32)align, !base); 329 330 return (void *)paddr; 331 } 332 333 void *sysmem_alloc_align(const char *name, phys_size_t size, ulong align) 334 { 335 return sysmem_alloc_align_base(name, 336 SYSMEM_ALLOC_ANYWHERE, 337 size, 338 align); 339 } 340 341 void *sysmem_alloc_base(const char *name, phys_addr_t base, phys_size_t size) 342 { 343 return sysmem_alloc_align_base(name, 344 base, 345 size, 346 SYSMEM_ALLOC_NO_ALIGN); 347 } 348 349 void *sysmem_alloc(const char *name, phys_size_t size) 350 { 351 return sysmem_alloc_align_base(name, 352 SYSMEM_ALLOC_ANYWHERE, 353 size, 354 SYSMEM_ALLOC_NO_ALIGN); 355 } 356 357 int sysmem_free(phys_addr_t base) 358 { 359 struct sysmem *sysmem = &plat_sysmem; 360 struct sysmem_property *prop; 361 struct list_head *node; 362 int found = 0; 363 int ret; 364 365 if (!sysmem_has_init()) 366 return -ENOSYS; 367 368 /* Find existence */ 369 list_for_each(node, &sysmem->allocated_head) { 370 prop = list_entry(node, struct sysmem_property, node); 371 if (prop->base == base) { 372 found = 1; 373 break; 374 } 375 } 376 377 if (!found) { 378 SYSMEM_E("Failed to free no allocated sysmem at 0x%lx\n", (ulong)base); 379 return -EINVAL; 380 } 381 382 ret = lmb_free(&sysmem->lmb, prop->base, prop->size); 383 if (ret >= 0) { 384 SYSMEM_D("Free: \"%s\", paddr=0x%lx, size=0x%lx\n", 385 prop->name, (ulong)prop->base, (ulong)prop->size); 386 sysmem->allocated_cnt--; 387 list_del(&prop->node); 388 free(prop); 389 } else { 390 SYSMEM_E("Failed to free \"%s\" at 0x%lx\n", prop->name, (ulong)base); 391 } 392 393 return (ret >= 0) ? 0 : ret; 394 } 395 396 int sysmem_init(void) 397 { 398 struct sysmem *sysmem = &plat_sysmem; 399 struct sysmem_check *check; 400 phys_addr_t mem_start; 401 phys_size_t mem_size; 402 int ret; 403 404 SYSMEM_I("init\n"); 405 406 lmb_init(&sysmem->lmb); 407 INIT_LIST_HEAD(&sysmem->allocated_head); 408 INIT_LIST_HEAD(&sysmem->reserved_head); 409 sysmem->allocated_cnt = 0; 410 sysmem->has_init = true; 411 412 /* Add all available system memory */ 413 #ifdef CONFIG_NR_DRAM_BANKS 414 int i; 415 416 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 417 ret = sysmem_add(gd->bd->bi_dram[i].start, 418 gd->bd->bi_dram[i].size); 419 if (ret) { 420 SYSMEM_E("Failed to add sysmem from bi_dram[%d]\n", i); 421 return ret; 422 } 423 } 424 #else 425 mem_start = env_get_bootm_low(); 426 mem_size = env_get_bootm_size(); 427 ret = sysmem_add(mem_start, mem_size); 428 if (ret) { 429 SYSMEM_E("Failed to add sysmem from bootm_low/size\n"); 430 return ret; 431 } 432 #endif 433 434 /* Reserved for arch */ 435 ret = arch_sysmem_reserve(sysmem); 436 if (ret) { 437 SYSMEM_E("Failed to reserve sysmem for arch\n"); 438 return ret; 439 } 440 441 /* Reserved for board */ 442 ret = board_sysmem_reserve(sysmem); 443 if (ret) { 444 SYSMEM_E("Failed to reserve sysmem for board\n"); 445 return ret; 446 } 447 448 /* Reserved for U-boot framework 'reserve_xxx()' */ 449 mem_start = gd->start_addr_sp - CONFIG_SYS_STACK_SIZE; 450 mem_size = gd->ram_top - mem_start; 451 check = (struct sysmem_check *)mem_start; 452 check->magic = SYSMEM_MAGIC; 453 454 ret = sysmem_reserve("U-Boot", mem_start, mem_size); 455 if (ret) { 456 SYSMEM_E("Failed to reserve sysmem for U-Boot framework\n"); 457 return ret; 458 } 459 460 sysmem_dump(); 461 462 return 0; 463 } 464 465 __weak int board_sysmem_reserve(struct sysmem *sysmem) 466 { 467 /* please define platform specific board_sysmem_reserve() */ 468 return 0; 469 } 470 471 __weak int arch_sysmem_reserve(struct sysmem *sysmem) 472 { 473 /* please define platform specific arch_sysmem_reserve() */ 474 return 0; 475 } 476