1483d0493SJoseph Chen // SPDX-License-Identifier: GPL-2.0 2483d0493SJoseph Chen /* 3483d0493SJoseph Chen * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd 4483d0493SJoseph Chen */ 5483d0493SJoseph Chen 6483d0493SJoseph Chen #include <common.h> 7483d0493SJoseph Chen #include <lmb.h> 8483d0493SJoseph Chen #include <bidram.h> 9483d0493SJoseph Chen #include <malloc.h> 10483d0493SJoseph Chen #include <sysmem.h> 11483d0493SJoseph Chen #include <asm/io.h> 12*d8e6f8d0SJoseph Chen #include <asm/arch/rk_atags.h> 13483d0493SJoseph Chen 14483d0493SJoseph Chen DECLARE_GLOBAL_DATA_PTR; 15483d0493SJoseph Chen 16483d0493SJoseph Chen #define MAX_BAD_MEMBLK 8 17483d0493SJoseph Chen 18483d0493SJoseph Chen #define BIDRAM_R(fmt, args...) printf(fmt, ##args) 19483d0493SJoseph Chen #define BIDRAM_I(fmt, args...) printf("Bidram: "fmt, ##args) 20483d0493SJoseph Chen #define BIDRAM_W(fmt, args...) printf("Bidram Warn: "fmt, ##args) 21483d0493SJoseph Chen #define BIDRAM_E(fmt, args...) printf("Bidram Error: "fmt, ##args) 22483d0493SJoseph Chen #define BIDRAM_D(fmt, args...) debug("Bidram Debug: "fmt, ##args) 23483d0493SJoseph Chen 24483d0493SJoseph Chen struct bidram plat_bidram __section(".data") = { .has_init = false, }; 25483d0493SJoseph Chen 26483d0493SJoseph Chen static int bidram_has_init(void) 27483d0493SJoseph Chen { 28483d0493SJoseph Chen if (!plat_bidram.has_init) { 29483d0493SJoseph Chen BIDRAM_E("Framework is not initialized\n"); 30483d0493SJoseph Chen return 0; 31483d0493SJoseph Chen } 32483d0493SJoseph Chen 33483d0493SJoseph Chen return 1; 34483d0493SJoseph Chen } 35483d0493SJoseph Chen 36483d0493SJoseph Chen void bidram_dump(void) 37483d0493SJoseph Chen { 38483d0493SJoseph Chen struct bidram *bidram = &plat_bidram; 39483d0493SJoseph Chen struct lmb *lmb = &bidram->lmb; 40483d0493SJoseph Chen struct memblock *mem; 41483d0493SJoseph Chen struct list_head *node; 42483d0493SJoseph Chen ulong memory_size = 0; 43483d0493SJoseph Chen ulong reserved_size = 0; 44483d0493SJoseph Chen ulong i; 45483d0493SJoseph Chen 46483d0493SJoseph Chen if (!bidram_has_init()) 47483d0493SJoseph Chen return; 48483d0493SJoseph Chen 49483d0493SJoseph Chen printf("\n\nbidram_dump_all:\n"); 50483d0493SJoseph Chen 51483d0493SJoseph Chen /* Memory pool */ 52483d0493SJoseph Chen printf(" --------------------------------------------------------------------\n"); 53483d0493SJoseph Chen for (i = 0; i < lmb->memory.cnt; i++) { 54483d0493SJoseph Chen memory_size += lmb->memory.region[i].size; 55483d0493SJoseph Chen printf(" memory.rgn[%ld].addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", i, 56483d0493SJoseph Chen (ulong)lmb->memory.region[i].base, 57483d0493SJoseph Chen (ulong)lmb->memory.region[i].base + 58483d0493SJoseph Chen (ulong)lmb->memory.region[i].size, 59483d0493SJoseph Chen (ulong)lmb->memory.region[i].size); 60483d0493SJoseph Chen } 61483d0493SJoseph Chen printf("\n memory.total = 0x%08lx (%ld MiB. %ld KiB)\n", 62483d0493SJoseph Chen (ulong)memory_size, 63483d0493SJoseph Chen SIZE_MB((ulong)memory_size), 64483d0493SJoseph Chen SIZE_KB((ulong)memory_size)); 65483d0493SJoseph Chen 66483d0493SJoseph Chen /* Reserved */ 67483d0493SJoseph Chen i = 0; 68483d0493SJoseph Chen printf(" --------------------------------------------------------------------\n"); 69483d0493SJoseph Chen list_for_each(node, &bidram->reserved_head) { 70483d0493SJoseph Chen mem = list_entry(node, struct memblock, node); 71483d0493SJoseph Chen reserved_size += mem->size; 72483d0493SJoseph Chen printf(" reserved.rgn[%ld].name = \"%s\"\n", i, mem->attr.name); 73483d0493SJoseph Chen printf(" .addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", 74483d0493SJoseph Chen (ulong)mem->base, (ulong)mem->base + (ulong)mem->size, 75483d0493SJoseph Chen (ulong)mem->size); 76483d0493SJoseph Chen i++; 77483d0493SJoseph Chen } 78483d0493SJoseph Chen printf("\n reserved.total = 0x%08lx (%ld MiB. %ld KiB)\n", 79483d0493SJoseph Chen (ulong)reserved_size, 80483d0493SJoseph Chen SIZE_MB((ulong)reserved_size), 81483d0493SJoseph Chen SIZE_KB((ulong)reserved_size)); 82483d0493SJoseph Chen 83483d0493SJoseph Chen /* LMB core reserved */ 84483d0493SJoseph Chen printf(" --------------------------------------------------------------------\n"); 85483d0493SJoseph Chen reserved_size = 0; 86483d0493SJoseph Chen for (i = 0; i < lmb->reserved.cnt; i++) { 87483d0493SJoseph Chen reserved_size += lmb->reserved.region[i].size; 88483d0493SJoseph Chen printf(" LMB.reserved[%ld].addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", i, 89483d0493SJoseph Chen (ulong)lmb->reserved.region[i].base, 90483d0493SJoseph Chen (ulong)lmb->reserved.region[i].base + 91483d0493SJoseph Chen (ulong)lmb->reserved.region[i].size, 92483d0493SJoseph Chen (ulong)lmb->reserved.region[i].size); 93483d0493SJoseph Chen } 94483d0493SJoseph Chen 95483d0493SJoseph Chen printf("\n reserved.core.total = 0x%08lx (%ld MiB. %ld KiB)\n", 96483d0493SJoseph Chen (ulong)reserved_size, 97483d0493SJoseph Chen SIZE_MB((ulong)reserved_size), 98483d0493SJoseph Chen SIZE_KB((ulong)reserved_size)); 99483d0493SJoseph Chen printf(" --------------------------------------------------------------------\n\n"); 100483d0493SJoseph Chen } 101483d0493SJoseph Chen 102483d0493SJoseph Chen static int bidram_add(phys_addr_t base, phys_size_t size) 103483d0493SJoseph Chen { 104483d0493SJoseph Chen struct bidram *bidram = &plat_bidram; 105483d0493SJoseph Chen int ret; 106483d0493SJoseph Chen 107483d0493SJoseph Chen if (!bidram_has_init()) 108483d0493SJoseph Chen return -ENOSYS; 109483d0493SJoseph Chen 110483d0493SJoseph Chen if (!size) 111483d0493SJoseph Chen return -EINVAL; 112483d0493SJoseph Chen 113483d0493SJoseph Chen ret = lmb_add(&bidram->lmb, base, size); 114483d0493SJoseph Chen if (ret < 0) 115483d0493SJoseph Chen BIDRAM_E("Failed to add bidram at 0x%08lx - 0x%08lx\n", 116483d0493SJoseph Chen (ulong)base, (ulong)(base + size)); 117483d0493SJoseph Chen 118483d0493SJoseph Chen return (ret >= 0) ? 0 : ret; 119483d0493SJoseph Chen } 120483d0493SJoseph Chen 121483d0493SJoseph Chen void bidram_gen_gd_bi_dram(void) 122483d0493SJoseph Chen { 1231d09cf29SJoseph Chen struct bidram *bidram = &plat_bidram; 124483d0493SJoseph Chen struct lmb *lmb = &plat_bidram.lmb; 125483d0493SJoseph Chen struct lmb_property *mem_rgn = lmb->memory.region; 126483d0493SJoseph Chen struct lmb_property *res_rgn = lmb->reserved.region; 127483d0493SJoseph Chen int rsv_cnt = lmb->reserved.cnt; 128483d0493SJoseph Chen int i, idx = 0; 129483d0493SJoseph Chen 130483d0493SJoseph Chen if (!gd || !gd->bd) { 131483d0493SJoseph Chen BIDRAM_D("Ignore bi dram bank update\n"); 132483d0493SJoseph Chen return; 133483d0493SJoseph Chen } 134483d0493SJoseph Chen 135356575c3SJoseph Chen /* 136356575c3SJoseph Chen * LBM default init: 137356575c3SJoseph Chen * lmb->reserved.cnt = 1; 138356575c3SJoseph Chen * lmb->reserved.region[0].base = 0; 139356575c3SJoseph Chen * lmb->reserved.region[0].size = 0; 140356575c3SJoseph Chen * 141356575c3SJoseph Chen * Here handle that: there is the only one dram bank available. 142356575c3SJoseph Chen */ 143356575c3SJoseph Chen if (rsv_cnt == 1 && !res_rgn[0].base && !res_rgn[0].size) { 144*d8e6f8d0SJoseph Chen gd->bd->bi_dram[idx].start = mem_rgn[0].base; 145*d8e6f8d0SJoseph Chen gd->bd->bi_dram[idx].size = mem_rgn[0].size; 146*d8e6f8d0SJoseph Chen idx++; 147356575c3SJoseph Chen goto done; 148356575c3SJoseph Chen } 149356575c3SJoseph Chen 150483d0493SJoseph Chen /* If reserved rgn is not from sdram start */ 151483d0493SJoseph Chen if (res_rgn[0].base != mem_rgn[0].base) { 152483d0493SJoseph Chen gd->bd->bi_dram[idx].start = mem_rgn[0].base; 153483d0493SJoseph Chen gd->bd->bi_dram[idx].size = res_rgn[0].base - 154483d0493SJoseph Chen gd->bd->bi_dram[idx].start; 155483d0493SJoseph Chen idx++; 156483d0493SJoseph Chen } 157483d0493SJoseph Chen 158483d0493SJoseph Chen /* 159483d0493SJoseph Chen * Note: If reserved rgn is not from sdram start, idx=1 now, otherwise 0. 160483d0493SJoseph Chen */ 161483d0493SJoseph Chen for (i = 0; i < rsv_cnt; i++, idx++) { 162483d0493SJoseph Chen if (res_rgn[i].base + res_rgn[i].size >= gd->ram_top) 163483d0493SJoseph Chen goto done; 164483d0493SJoseph Chen 165483d0493SJoseph Chen gd->bd->bi_dram[idx].start = res_rgn[i].base + res_rgn[i].size; 166483d0493SJoseph Chen if (i + 1 < rsv_cnt) 167483d0493SJoseph Chen gd->bd->bi_dram[idx].size = res_rgn[i + 1].base - 168483d0493SJoseph Chen gd->bd->bi_dram[idx].start; 169483d0493SJoseph Chen else 170483d0493SJoseph Chen gd->bd->bi_dram[idx].size = gd->ram_top - 171483d0493SJoseph Chen gd->bd->bi_dram[idx].start; 172483d0493SJoseph Chen } 173483d0493SJoseph Chen done: 174*d8e6f8d0SJoseph Chen /* Append 4GB+ memory blocks and extend ram top */ 1751d09cf29SJoseph Chen if (bidram->fixup) { 176*d8e6f8d0SJoseph Chen /* extend ram top */ 177*d8e6f8d0SJoseph Chen if (gd->ram_top_ext_size) { 178*d8e6f8d0SJoseph Chen int pos = idx - 1; 179*d8e6f8d0SJoseph Chen ulong top; 180*d8e6f8d0SJoseph Chen 181*d8e6f8d0SJoseph Chen if (gd->bd->bi_dram[pos].start + 182*d8e6f8d0SJoseph Chen gd->bd->bi_dram[pos].size == gd->ram_top) { 183*d8e6f8d0SJoseph Chen top = gd->bd->bi_dram[pos].start + gd->bd->bi_dram[pos].size; 184*d8e6f8d0SJoseph Chen gd->bd->bi_dram[pos].size += gd->ram_top_ext_size; 185*d8e6f8d0SJoseph Chen printf("Extend top: 0x%08lx -> 0x%08lx\n", 186*d8e6f8d0SJoseph Chen top, top + (ulong)gd->ram_top_ext_size); 187*d8e6f8d0SJoseph Chen } 188*d8e6f8d0SJoseph Chen } 189*d8e6f8d0SJoseph Chen 190*d8e6f8d0SJoseph Chen /* append 4GB+ */ 1911d09cf29SJoseph Chen for (i = 0; i < MEM_RESV_COUNT; i++) { 1921d09cf29SJoseph Chen if (!bidram->size_u64[i]) 1931d09cf29SJoseph Chen continue; 1941d09cf29SJoseph Chen gd->bd->bi_dram[idx].start = bidram->base_u64[i]; 1951d09cf29SJoseph Chen gd->bd->bi_dram[idx].size = bidram->size_u64[i]; 1961d09cf29SJoseph Chen BIDRAM_D("FIXUP: gd->bi_dram[%d]: start=0x%llx, size=0x%llx\n", 1971d09cf29SJoseph Chen idx, bidram->base_u64[i], bidram->size_u64[i]); 1981d09cf29SJoseph Chen idx++; 199483d0493SJoseph Chen } 200483d0493SJoseph Chen } 201483d0493SJoseph Chen 2021d09cf29SJoseph Chen for (i = 0; i < idx; i++) { 2031d09cf29SJoseph Chen BIDRAM_D("GEN: gd->bi_dram[%d]: start=0x%llx, end=0x%llx\n", 2041d09cf29SJoseph Chen i, (u64)gd->bd->bi_dram[i].start, 2051d09cf29SJoseph Chen (u64)gd->bd->bi_dram[i].start + 2061d09cf29SJoseph Chen (u64)gd->bd->bi_dram[i].size); 2071d09cf29SJoseph Chen } 2081d09cf29SJoseph Chen } 2091d09cf29SJoseph Chen 2101d09cf29SJoseph Chen int bidram_fixup(void) 2111d09cf29SJoseph Chen { 2121d09cf29SJoseph Chen struct bidram *bidram = &plat_bidram; 2131d09cf29SJoseph Chen 2141d09cf29SJoseph Chen bidram->fixup = true; 2151d09cf29SJoseph Chen bidram_gen_gd_bi_dram(); 2161d09cf29SJoseph Chen 2171d09cf29SJoseph Chen return 0; 2181d09cf29SJoseph Chen } 2191d09cf29SJoseph Chen 2201d09cf29SJoseph Chen u64 bidram_append_size(void) 2211d09cf29SJoseph Chen { 2221d09cf29SJoseph Chen struct bidram *bidram = &plat_bidram; 2231d09cf29SJoseph Chen u64 size = 0; 2241d09cf29SJoseph Chen int i; 2251d09cf29SJoseph Chen 2261d09cf29SJoseph Chen /* 4GB+ */ 2271d09cf29SJoseph Chen for (i = 0; i < MEM_RESV_COUNT; i++) 2281d09cf29SJoseph Chen size += bidram->size_u64[i]; 2291d09cf29SJoseph Chen 230*d8e6f8d0SJoseph Chen if (gd->ram_top_ext_size) 231*d8e6f8d0SJoseph Chen size += gd->ram_top_ext_size; 232*d8e6f8d0SJoseph Chen 2331d09cf29SJoseph Chen return size; 2341d09cf29SJoseph Chen } 2351d09cf29SJoseph Chen 236483d0493SJoseph Chen static int bidram_is_overlap(phys_addr_t base1, phys_size_t size1, 237483d0493SJoseph Chen phys_addr_t base2, phys_size_t size2) 238483d0493SJoseph Chen { 239483d0493SJoseph Chen return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); 240483d0493SJoseph Chen } 241483d0493SJoseph Chen 242fc7ff0f0SJoseph Chen struct memblock *bidram_reserved_is_overlap(phys_addr_t base, phys_size_t size) 243fc7ff0f0SJoseph Chen { 244fc7ff0f0SJoseph Chen struct bidram *bidram = &plat_bidram; 245fc7ff0f0SJoseph Chen struct list_head *node; 246fc7ff0f0SJoseph Chen struct memblock *mem; 247fc7ff0f0SJoseph Chen 248fc7ff0f0SJoseph Chen if (!bidram_has_init()) 249fc7ff0f0SJoseph Chen return false; 250fc7ff0f0SJoseph Chen 251fc7ff0f0SJoseph Chen list_for_each(node, &bidram->reserved_head) { 252fc7ff0f0SJoseph Chen mem = list_entry(node, struct memblock, node); 253fc7ff0f0SJoseph Chen if (bidram_is_overlap(mem->base, mem->size, base, size)) 254fc7ff0f0SJoseph Chen return mem; 255fc7ff0f0SJoseph Chen } 256fc7ff0f0SJoseph Chen 257fc7ff0f0SJoseph Chen return NULL; 258fc7ff0f0SJoseph Chen } 259fc7ff0f0SJoseph Chen 260483d0493SJoseph Chen static int bidram_core_reserve(enum memblk_id id, const char *mem_name, 261483d0493SJoseph Chen phys_addr_t base, phys_size_t size) 262483d0493SJoseph Chen { 263483d0493SJoseph Chen struct bidram *bidram = &plat_bidram; 264483d0493SJoseph Chen struct memblk_attr attr; 265483d0493SJoseph Chen struct memblock *mem; 266483d0493SJoseph Chen struct list_head *node; 267483d0493SJoseph Chen const char *name; 268483d0493SJoseph Chen int ret; 269483d0493SJoseph Chen 270483d0493SJoseph Chen if (!bidram_has_init()) 271483d0493SJoseph Chen return -ENOSYS; 272483d0493SJoseph Chen 273c01d4489SJoseph Chen if (id == MEM_BY_NAME) { 274483d0493SJoseph Chen if (!mem_name) { 275483d0493SJoseph Chen BIDRAM_E("NULL name for reserve bidram\n"); 276483d0493SJoseph Chen return -EINVAL; 277483d0493SJoseph Chen } else { 278483d0493SJoseph Chen name = mem_name; 279483d0493SJoseph Chen } 280483d0493SJoseph Chen } else { 281c01d4489SJoseph Chen if (id > MEM_UNK && id < MEM_MAX) { 282483d0493SJoseph Chen attr = mem_attr[id]; 283483d0493SJoseph Chen name = attr.name; 284483d0493SJoseph Chen } else { 285483d0493SJoseph Chen BIDRAM_E("Unsupport memblk id %d for reserve bidram\n", id); 286483d0493SJoseph Chen return -EINVAL; 287483d0493SJoseph Chen } 288483d0493SJoseph Chen } 289483d0493SJoseph Chen 290483d0493SJoseph Chen if (!name) { 291483d0493SJoseph Chen BIDRAM_E("NULL name for reserved bidram\n"); 292483d0493SJoseph Chen return -EINVAL; 293483d0493SJoseph Chen } 294483d0493SJoseph Chen 295483d0493SJoseph Chen if (!size) 296483d0493SJoseph Chen return 0; 297483d0493SJoseph Chen 298483d0493SJoseph Chen /* Check overlap */ 299483d0493SJoseph Chen list_for_each(node, &bidram->reserved_head) { 300483d0493SJoseph Chen mem = list_entry(node, struct memblock, node); 301356575c3SJoseph Chen BIDRAM_D("Has reserved: %s 0x%08lx - 0x%08lx\n", 302483d0493SJoseph Chen mem->attr.name, (ulong)mem->base, 303483d0493SJoseph Chen (ulong)(mem->base + mem->size)); 304483d0493SJoseph Chen if (!strcmp(mem->attr.name, name)) { 305483d0493SJoseph Chen BIDRAM_E("Failed to double reserve for existence \"%s\"\n", name); 306483d0493SJoseph Chen return -EEXIST; 307483d0493SJoseph Chen } else if (bidram_is_overlap(mem->base, mem->size, base, size)) { 308483d0493SJoseph Chen BIDRAM_D("\"%s\" (0x%08lx - 0x%08lx) reserve is " 309483d0493SJoseph Chen "overlap with existence \"%s\" (0x%08lx - " 310483d0493SJoseph Chen "0x%08lx)\n", 311483d0493SJoseph Chen name, (ulong)base, (ulong)(base + size), mem->attr.name, 312483d0493SJoseph Chen (ulong)mem->base, (ulong)(mem->base + mem->size)); 313483d0493SJoseph Chen } 314483d0493SJoseph Chen } 315483d0493SJoseph Chen 316356575c3SJoseph Chen BIDRAM_D("Reserve: \"%s\" 0x%08lx - 0x%08lx\n", 317356575c3SJoseph Chen name, (ulong)base, (ulong)(base + size)); 318356575c3SJoseph Chen 319483d0493SJoseph Chen ret = lmb_reserve(&bidram->lmb, base, size); 320483d0493SJoseph Chen if (ret >= 0) { 321483d0493SJoseph Chen mem = malloc(sizeof(*mem)); 322483d0493SJoseph Chen if (!mem) { 323483d0493SJoseph Chen BIDRAM_E("No memory for \"%s\" reserve bidram\n", name); 324483d0493SJoseph Chen return -ENOMEM; 325483d0493SJoseph Chen } 326483d0493SJoseph Chen 327483d0493SJoseph Chen #ifdef CONFIG_SYSMEM 328483d0493SJoseph Chen /* Sync to sysmem */ 329483d0493SJoseph Chen if (sysmem_has_init()) { 330483d0493SJoseph Chen void *paddr; 331483d0493SJoseph Chen 332c01d4489SJoseph Chen if (id == MEM_BY_NAME) 333483d0493SJoseph Chen paddr = sysmem_alloc_base_by_name(name, base, size); 334483d0493SJoseph Chen else 335483d0493SJoseph Chen paddr = sysmem_alloc_base(id, base, size); 336483d0493SJoseph Chen if (!paddr) { 337483d0493SJoseph Chen BIDRAM_E("Sync \"%s\" to sysmem failed\n", name); 338483d0493SJoseph Chen return -ENOMEM; 339483d0493SJoseph Chen } 340483d0493SJoseph Chen } 341483d0493SJoseph Chen #endif 342483d0493SJoseph Chen mem->base = base; 343483d0493SJoseph Chen mem->size = size; 344c01d4489SJoseph Chen if (id == MEM_BY_NAME) { 345483d0493SJoseph Chen mem->attr.name = name; 346483d0493SJoseph Chen mem->attr.flags = 0; 347483d0493SJoseph Chen } else { 348483d0493SJoseph Chen mem->attr = attr; 349483d0493SJoseph Chen } 350483d0493SJoseph Chen list_add_tail(&mem->node, &bidram->reserved_head); 351483d0493SJoseph Chen } else { 352483d0493SJoseph Chen BIDRAM_E("Failed to reserve \"%s\" 0x%08lx - 0x%08lx\n", 353483d0493SJoseph Chen name, (ulong)base, (ulong)(base + size)); 354483d0493SJoseph Chen return -EINVAL; 355483d0493SJoseph Chen } 356483d0493SJoseph Chen 357483d0493SJoseph Chen return 0; 358483d0493SJoseph Chen } 359483d0493SJoseph Chen 360483d0493SJoseph Chen int bidram_reserve(enum memblk_id id, phys_addr_t base, phys_size_t size) 361483d0493SJoseph Chen { 362483d0493SJoseph Chen int ret; 363483d0493SJoseph Chen 364483d0493SJoseph Chen ret = bidram_core_reserve(id, NULL, base, size); 365483d0493SJoseph Chen if (!ret) 366483d0493SJoseph Chen bidram_gen_gd_bi_dram(); 367483d0493SJoseph Chen else 368483d0493SJoseph Chen bidram_dump(); 369483d0493SJoseph Chen 370483d0493SJoseph Chen return ret; 371483d0493SJoseph Chen } 372483d0493SJoseph Chen 373483d0493SJoseph Chen int bidram_reserve_by_name(const char *name, 374483d0493SJoseph Chen phys_addr_t base, phys_size_t size) 375483d0493SJoseph Chen { 376483d0493SJoseph Chen int ret; 377483d0493SJoseph Chen 378c01d4489SJoseph Chen ret = bidram_core_reserve(MEM_BY_NAME, name, base, size); 379483d0493SJoseph Chen if (!ret) 380483d0493SJoseph Chen bidram_gen_gd_bi_dram(); 381483d0493SJoseph Chen else 382483d0493SJoseph Chen bidram_dump(); 383483d0493SJoseph Chen 384483d0493SJoseph Chen return ret; 385483d0493SJoseph Chen } 386483d0493SJoseph Chen 387483d0493SJoseph Chen int bidram_initr(void) 388483d0493SJoseph Chen { 389483d0493SJoseph Chen return !bidram_get_ram_size(); 390483d0493SJoseph Chen } 391483d0493SJoseph Chen 392483d0493SJoseph Chen phys_size_t bidram_get_ram_size(void) 393483d0493SJoseph Chen { 394483d0493SJoseph Chen struct bidram *bidram = &plat_bidram; 395483d0493SJoseph Chen struct memblock bad[MAX_BAD_MEMBLK]; 396483d0493SJoseph Chen struct memblock *list; 397483d0493SJoseph Chen phys_size_t ram_addr_end = CONFIG_SYS_SDRAM_BASE; 398483d0493SJoseph Chen phys_addr_t end_addr; 399483d0493SJoseph Chen parse_fn_t parse_fn; 400483d0493SJoseph Chen int i, count, ret; 4011d09cf29SJoseph Chen int bad_cnt = 0, n = 0; 402483d0493SJoseph Chen char bad_name[12]; 403483d0493SJoseph Chen 404483d0493SJoseph Chen parse_fn = board_bidram_parse_fn(); 405483d0493SJoseph Chen if (!parse_fn) { 406483d0493SJoseph Chen BIDRAM_E("Can't find dram parse fn\n"); 407483d0493SJoseph Chen return 0; 408483d0493SJoseph Chen } 409483d0493SJoseph Chen 410483d0493SJoseph Chen list = parse_fn(&count); 411483d0493SJoseph Chen if (!list) { 412483d0493SJoseph Chen BIDRAM_E("Can't get dram banks\n"); 413483d0493SJoseph Chen return 0; 414483d0493SJoseph Chen } 415483d0493SJoseph Chen 416483d0493SJoseph Chen if (count > CONFIG_NR_DRAM_BANKS) { 417483d0493SJoseph Chen BIDRAM_E("Too many dram banks, %d is over max: %d\n", 418483d0493SJoseph Chen count, CONFIG_NR_DRAM_BANKS); 419483d0493SJoseph Chen return 0; 420483d0493SJoseph Chen } 421483d0493SJoseph Chen 422483d0493SJoseph Chen /* Initial plat_bidram */ 423483d0493SJoseph Chen lmb_init(&bidram->lmb); 424483d0493SJoseph Chen INIT_LIST_HEAD(&bidram->reserved_head); 425483d0493SJoseph Chen bidram->has_init = true; 426483d0493SJoseph Chen 427483d0493SJoseph Chen /* Initial memory pool */ 428483d0493SJoseph Chen for (i = 0; i < count; i++) { 429483d0493SJoseph Chen BIDRAM_D("Add bank[%d] start=0x%08lx, end=0x%08lx\n", 430483d0493SJoseph Chen i, (ulong)list[i].base, 431483d0493SJoseph Chen (ulong)list[i].base + (ulong)list[i].size); 432483d0493SJoseph Chen 4331d09cf29SJoseph Chen if (!list[i].size) { 4341d09cf29SJoseph Chen /* handle 4GB+ */ 4351d09cf29SJoseph Chen if (list[i].size_u64 && n < MEM_RESV_COUNT) { 4361d09cf29SJoseph Chen bidram->base_u64[n] = list[i].base_u64; 4371d09cf29SJoseph Chen bidram->size_u64[n] = list[i].size_u64; 4381d09cf29SJoseph Chen n++; 4391d09cf29SJoseph Chen } 440483d0493SJoseph Chen continue; 4411d09cf29SJoseph Chen } 442483d0493SJoseph Chen 443483d0493SJoseph Chen /* We assume the last block gives the ram addr end */ 444483d0493SJoseph Chen ram_addr_end = list[i].base + list[i].size; 445483d0493SJoseph Chen 446483d0493SJoseph Chen /* This is a bad dram bank? record it */ 447483d0493SJoseph Chen if (i > 0) { 448483d0493SJoseph Chen end_addr = list[i - 1].base + list[i - 1].size; 449483d0493SJoseph Chen 450483d0493SJoseph Chen if (list[i].base != end_addr) { 451483d0493SJoseph Chen snprintf(bad_name, 12, "%s%d", "BAD_RAM.", i - 1); 452483d0493SJoseph Chen bad[bad_cnt].attr.name = strdup(bad_name); 453483d0493SJoseph Chen bad[bad_cnt].base = end_addr; 454483d0493SJoseph Chen bad[bad_cnt].size = list[i].base - end_addr; 455483d0493SJoseph Chen bad_cnt++; 456483d0493SJoseph Chen if (bad_cnt > MAX_BAD_MEMBLK) { 457483d0493SJoseph Chen BIDRAM_E("Too many bad memory blocks\n"); 458483d0493SJoseph Chen return 0; 459483d0493SJoseph Chen } 460483d0493SJoseph Chen } 461483d0493SJoseph Chen } 462483d0493SJoseph Chen } 463483d0493SJoseph Chen 4641d09cf29SJoseph Chen ret = bidram_add(CONFIG_SYS_SDRAM_BASE, 4651d09cf29SJoseph Chen ram_addr_end - CONFIG_SYS_SDRAM_BASE); 4661d09cf29SJoseph Chen if (ret) { 4671d09cf29SJoseph Chen BIDRAM_E("Failed to add bidram from bi_dram[%d]\n", i); 4681d09cf29SJoseph Chen return 0; 4691d09cf29SJoseph Chen } 4701d09cf29SJoseph Chen 471483d0493SJoseph Chen /* Reserve bad dram bank after bidram_add(), treat as reserved region */ 472483d0493SJoseph Chen for (i = 0; i < bad_cnt; i++) { 473483d0493SJoseph Chen if (gd->flags & GD_FLG_RELOC) 474483d0493SJoseph Chen BIDRAM_R("Bad memblk%d: 0x%08lx - 0x%08lx\n", 475483d0493SJoseph Chen i, (ulong)bad[i].base, 476483d0493SJoseph Chen (ulong)bad[i].base + (ulong)bad[i].size); 477483d0493SJoseph Chen 478483d0493SJoseph Chen ret = bidram_reserve_by_name(bad[i].attr.name, 479483d0493SJoseph Chen bad[i].base, bad[i].size); 480483d0493SJoseph Chen if (ret) { 481483d0493SJoseph Chen BIDRAM_E("Failed to add bad memblk[%d]\n", i); 482483d0493SJoseph Chen return 0; 483483d0493SJoseph Chen } 484483d0493SJoseph Chen } 485483d0493SJoseph Chen 486483d0493SJoseph Chen /* Reserved for board */ 487483d0493SJoseph Chen ret = board_bidram_reserve(bidram); 488483d0493SJoseph Chen if (ret) { 489483d0493SJoseph Chen BIDRAM_E("Failed to reserve bidram for board\n"); 490483d0493SJoseph Chen return 0; 491483d0493SJoseph Chen } 492483d0493SJoseph Chen 493483d0493SJoseph Chen BIDRAM_D("DRAM size: 0x%08lx\n", 494483d0493SJoseph Chen (ulong)ram_addr_end - CONFIG_SYS_SDRAM_BASE); 495483d0493SJoseph Chen 496483d0493SJoseph Chen #ifdef DEBUG 497483d0493SJoseph Chen bidram_dump(); 498483d0493SJoseph Chen #endif 499483d0493SJoseph Chen 500483d0493SJoseph Chen return (ram_addr_end - CONFIG_SYS_SDRAM_BASE); 501483d0493SJoseph Chen } 502483d0493SJoseph Chen 503483d0493SJoseph Chen __weak parse_fn_t board_bidram_parse_fn(void) 504483d0493SJoseph Chen { 505483d0493SJoseph Chen /* please define platform specific board_bidram_parse_fn() */ 506483d0493SJoseph Chen return NULL; 507483d0493SJoseph Chen } 508483d0493SJoseph Chen 509483d0493SJoseph Chen __weak int board_bidram_reserve(struct bidram *bidram) 510483d0493SJoseph Chen { 511483d0493SJoseph Chen /* please define platform specific board_bidram_reserve() */ 512483d0493SJoseph Chen return 0; 513483d0493SJoseph Chen } 514483d0493SJoseph Chen 5152fe84ae1SJoseph Chen static int do_bidram_dump(cmd_tbl_t *cmdtp, int flag, 516483d0493SJoseph Chen int argc, char *const argv[]) 517483d0493SJoseph Chen { 518483d0493SJoseph Chen bidram_dump(); 519483d0493SJoseph Chen return 0; 520483d0493SJoseph Chen } 521483d0493SJoseph Chen 522483d0493SJoseph Chen U_BOOT_CMD( 5232fe84ae1SJoseph Chen bidram_dump, 1, 1, do_bidram_dump, 524483d0493SJoseph Chen "Dump bidram layout", 525483d0493SJoseph Chen "" 526483d0493SJoseph Chen ); 527