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> 12483d0493SJoseph Chen 13483d0493SJoseph Chen DECLARE_GLOBAL_DATA_PTR; 14483d0493SJoseph Chen 15483d0493SJoseph Chen #define MAX_BAD_MEMBLK 8 16483d0493SJoseph Chen 17483d0493SJoseph Chen #define BIDRAM_R(fmt, args...) printf(fmt, ##args) 18483d0493SJoseph Chen #define BIDRAM_I(fmt, args...) printf("Bidram: "fmt, ##args) 19483d0493SJoseph Chen #define BIDRAM_W(fmt, args...) printf("Bidram Warn: "fmt, ##args) 20483d0493SJoseph Chen #define BIDRAM_E(fmt, args...) printf("Bidram Error: "fmt, ##args) 21483d0493SJoseph Chen #define BIDRAM_D(fmt, args...) debug("Bidram Debug: "fmt, ##args) 22483d0493SJoseph Chen 23483d0493SJoseph Chen struct bidram plat_bidram __section(".data") = { .has_init = false, }; 24483d0493SJoseph Chen 25483d0493SJoseph Chen static int bidram_has_init(void) 26483d0493SJoseph Chen { 27483d0493SJoseph Chen if (!plat_bidram.has_init) { 28483d0493SJoseph Chen BIDRAM_E("Framework is not initialized\n"); 29483d0493SJoseph Chen return 0; 30483d0493SJoseph Chen } 31483d0493SJoseph Chen 32483d0493SJoseph Chen return 1; 33483d0493SJoseph Chen } 34483d0493SJoseph Chen 35483d0493SJoseph Chen void bidram_dump(void) 36483d0493SJoseph Chen { 37483d0493SJoseph Chen struct bidram *bidram = &plat_bidram; 38483d0493SJoseph Chen struct lmb *lmb = &bidram->lmb; 39483d0493SJoseph Chen struct memblock *mem; 40483d0493SJoseph Chen struct list_head *node; 41483d0493SJoseph Chen ulong memory_size = 0; 42483d0493SJoseph Chen ulong reserved_size = 0; 43483d0493SJoseph Chen ulong i; 44483d0493SJoseph Chen 45483d0493SJoseph Chen if (!bidram_has_init()) 46483d0493SJoseph Chen return; 47483d0493SJoseph Chen 48483d0493SJoseph Chen printf("\n\nbidram_dump_all:\n"); 49483d0493SJoseph Chen 50483d0493SJoseph Chen /* Memory pool */ 51483d0493SJoseph Chen printf(" --------------------------------------------------------------------\n"); 52483d0493SJoseph Chen for (i = 0; i < lmb->memory.cnt; i++) { 53483d0493SJoseph Chen memory_size += lmb->memory.region[i].size; 54483d0493SJoseph Chen printf(" memory.rgn[%ld].addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", i, 55483d0493SJoseph Chen (ulong)lmb->memory.region[i].base, 56483d0493SJoseph Chen (ulong)lmb->memory.region[i].base + 57483d0493SJoseph Chen (ulong)lmb->memory.region[i].size, 58483d0493SJoseph Chen (ulong)lmb->memory.region[i].size); 59483d0493SJoseph Chen } 60483d0493SJoseph Chen printf("\n memory.total = 0x%08lx (%ld MiB. %ld KiB)\n", 61483d0493SJoseph Chen (ulong)memory_size, 62483d0493SJoseph Chen SIZE_MB((ulong)memory_size), 63483d0493SJoseph Chen SIZE_KB((ulong)memory_size)); 64483d0493SJoseph Chen 65483d0493SJoseph Chen /* Reserved */ 66483d0493SJoseph Chen i = 0; 67483d0493SJoseph Chen printf(" --------------------------------------------------------------------\n"); 68483d0493SJoseph Chen list_for_each(node, &bidram->reserved_head) { 69483d0493SJoseph Chen mem = list_entry(node, struct memblock, node); 70483d0493SJoseph Chen reserved_size += mem->size; 71483d0493SJoseph Chen printf(" reserved.rgn[%ld].name = \"%s\"\n", i, mem->attr.name); 72483d0493SJoseph Chen printf(" .addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", 73483d0493SJoseph Chen (ulong)mem->base, (ulong)mem->base + (ulong)mem->size, 74483d0493SJoseph Chen (ulong)mem->size); 75483d0493SJoseph Chen i++; 76483d0493SJoseph Chen } 77483d0493SJoseph Chen printf("\n reserved.total = 0x%08lx (%ld MiB. %ld KiB)\n", 78483d0493SJoseph Chen (ulong)reserved_size, 79483d0493SJoseph Chen SIZE_MB((ulong)reserved_size), 80483d0493SJoseph Chen SIZE_KB((ulong)reserved_size)); 81483d0493SJoseph Chen 82483d0493SJoseph Chen /* LMB core reserved */ 83483d0493SJoseph Chen printf(" --------------------------------------------------------------------\n"); 84483d0493SJoseph Chen reserved_size = 0; 85483d0493SJoseph Chen for (i = 0; i < lmb->reserved.cnt; i++) { 86483d0493SJoseph Chen reserved_size += lmb->reserved.region[i].size; 87483d0493SJoseph Chen printf(" LMB.reserved[%ld].addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", i, 88483d0493SJoseph Chen (ulong)lmb->reserved.region[i].base, 89483d0493SJoseph Chen (ulong)lmb->reserved.region[i].base + 90483d0493SJoseph Chen (ulong)lmb->reserved.region[i].size, 91483d0493SJoseph Chen (ulong)lmb->reserved.region[i].size); 92483d0493SJoseph Chen } 93483d0493SJoseph Chen 94483d0493SJoseph Chen printf("\n reserved.core.total = 0x%08lx (%ld MiB. %ld KiB)\n", 95483d0493SJoseph Chen (ulong)reserved_size, 96483d0493SJoseph Chen SIZE_MB((ulong)reserved_size), 97483d0493SJoseph Chen SIZE_KB((ulong)reserved_size)); 98483d0493SJoseph Chen printf(" --------------------------------------------------------------------\n\n"); 99483d0493SJoseph Chen } 100483d0493SJoseph Chen 101483d0493SJoseph Chen static int bidram_add(phys_addr_t base, phys_size_t size) 102483d0493SJoseph Chen { 103483d0493SJoseph Chen struct bidram *bidram = &plat_bidram; 104483d0493SJoseph Chen int ret; 105483d0493SJoseph Chen 106483d0493SJoseph Chen if (!bidram_has_init()) 107483d0493SJoseph Chen return -ENOSYS; 108483d0493SJoseph Chen 109483d0493SJoseph Chen if (!size) 110483d0493SJoseph Chen return -EINVAL; 111483d0493SJoseph Chen 112483d0493SJoseph Chen ret = lmb_add(&bidram->lmb, base, size); 113483d0493SJoseph Chen if (ret < 0) 114483d0493SJoseph Chen BIDRAM_E("Failed to add bidram at 0x%08lx - 0x%08lx\n", 115483d0493SJoseph Chen (ulong)base, (ulong)(base + size)); 116483d0493SJoseph Chen 117483d0493SJoseph Chen return (ret >= 0) ? 0 : ret; 118483d0493SJoseph Chen } 119483d0493SJoseph Chen 120483d0493SJoseph Chen void bidram_gen_gd_bi_dram(void) 121483d0493SJoseph Chen { 122483d0493SJoseph Chen struct lmb *lmb = &plat_bidram.lmb; 123483d0493SJoseph Chen struct lmb_property *mem_rgn = lmb->memory.region; 124483d0493SJoseph Chen struct lmb_property *res_rgn = lmb->reserved.region; 125483d0493SJoseph Chen int rsv_cnt = lmb->reserved.cnt; 126483d0493SJoseph Chen int i, idx = 0; 127483d0493SJoseph Chen 128483d0493SJoseph Chen if (!gd || !gd->bd) { 129483d0493SJoseph Chen BIDRAM_D("Ignore bi dram bank update\n"); 130483d0493SJoseph Chen return; 131483d0493SJoseph Chen } 132483d0493SJoseph Chen 133356575c3SJoseph Chen /* 134356575c3SJoseph Chen * LBM default init: 135356575c3SJoseph Chen * lmb->reserved.cnt = 1; 136356575c3SJoseph Chen * lmb->reserved.region[0].base = 0; 137356575c3SJoseph Chen * lmb->reserved.region[0].size = 0; 138356575c3SJoseph Chen * 139356575c3SJoseph Chen * Here handle that: there is the only one dram bank available. 140356575c3SJoseph Chen */ 141356575c3SJoseph Chen if (rsv_cnt == 1 && !res_rgn[0].base && !res_rgn[0].size) { 142356575c3SJoseph Chen gd->bd->bi_dram[0].start = mem_rgn[0].base; 143356575c3SJoseph Chen gd->bd->bi_dram[0].size = mem_rgn[0].size; 144356575c3SJoseph Chen goto done; 145356575c3SJoseph Chen } 146356575c3SJoseph Chen 147483d0493SJoseph Chen /* If reserved rgn is not from sdram start */ 148483d0493SJoseph Chen if (res_rgn[0].base != mem_rgn[0].base) { 149483d0493SJoseph Chen gd->bd->bi_dram[idx].start = mem_rgn[0].base; 150483d0493SJoseph Chen gd->bd->bi_dram[idx].size = res_rgn[0].base - 151483d0493SJoseph Chen gd->bd->bi_dram[idx].start; 152483d0493SJoseph Chen idx++; 153483d0493SJoseph Chen } 154483d0493SJoseph Chen 155483d0493SJoseph Chen /* 156483d0493SJoseph Chen * Note: If reserved rgn is not from sdram start, idx=1 now, otherwise 0. 157483d0493SJoseph Chen */ 158483d0493SJoseph Chen for (i = 0; i < rsv_cnt; i++, idx++) { 159483d0493SJoseph Chen if (res_rgn[i].base + res_rgn[i].size >= gd->ram_top) 160483d0493SJoseph Chen goto done; 161483d0493SJoseph Chen 162483d0493SJoseph Chen gd->bd->bi_dram[idx].start = res_rgn[i].base + res_rgn[i].size; 163483d0493SJoseph Chen if (i + 1 < rsv_cnt) 164483d0493SJoseph Chen gd->bd->bi_dram[idx].size = res_rgn[i + 1].base - 165483d0493SJoseph Chen gd->bd->bi_dram[idx].start; 166483d0493SJoseph Chen else 167483d0493SJoseph Chen gd->bd->bi_dram[idx].size = gd->ram_top - 168483d0493SJoseph Chen gd->bd->bi_dram[idx].start; 169483d0493SJoseph Chen } 170483d0493SJoseph Chen done: 171483d0493SJoseph Chen for (i = 0; i < idx; i++) { 172483d0493SJoseph Chen BIDRAM_D("gd bi_dram[%d]: start=0x%08lx, end=0x%08lx\n", 173483d0493SJoseph Chen i, (ulong)gd->bd->bi_dram[i].start, 174483d0493SJoseph Chen (ulong)gd->bd->bi_dram[i].start + 175483d0493SJoseph Chen (ulong)gd->bd->bi_dram[i].size); 176483d0493SJoseph Chen } 177483d0493SJoseph Chen } 178483d0493SJoseph Chen 179483d0493SJoseph Chen static int bidram_is_overlap(phys_addr_t base1, phys_size_t size1, 180483d0493SJoseph Chen phys_addr_t base2, phys_size_t size2) 181483d0493SJoseph Chen { 182483d0493SJoseph Chen return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); 183483d0493SJoseph Chen } 184483d0493SJoseph Chen 185*fc7ff0f0SJoseph Chen struct memblock *bidram_reserved_is_overlap(phys_addr_t base, phys_size_t size) 186*fc7ff0f0SJoseph Chen { 187*fc7ff0f0SJoseph Chen struct bidram *bidram = &plat_bidram; 188*fc7ff0f0SJoseph Chen struct list_head *node; 189*fc7ff0f0SJoseph Chen struct memblock *mem; 190*fc7ff0f0SJoseph Chen 191*fc7ff0f0SJoseph Chen if (!bidram_has_init()) 192*fc7ff0f0SJoseph Chen return false; 193*fc7ff0f0SJoseph Chen 194*fc7ff0f0SJoseph Chen list_for_each(node, &bidram->reserved_head) { 195*fc7ff0f0SJoseph Chen mem = list_entry(node, struct memblock, node); 196*fc7ff0f0SJoseph Chen if (bidram_is_overlap(mem->base, mem->size, base, size)) 197*fc7ff0f0SJoseph Chen return mem; 198*fc7ff0f0SJoseph Chen } 199*fc7ff0f0SJoseph Chen 200*fc7ff0f0SJoseph Chen return NULL; 201*fc7ff0f0SJoseph Chen } 202*fc7ff0f0SJoseph Chen 203483d0493SJoseph Chen static int bidram_core_reserve(enum memblk_id id, const char *mem_name, 204483d0493SJoseph Chen phys_addr_t base, phys_size_t size) 205483d0493SJoseph Chen { 206483d0493SJoseph Chen struct bidram *bidram = &plat_bidram; 207483d0493SJoseph Chen struct memblk_attr attr; 208483d0493SJoseph Chen struct memblock *mem; 209483d0493SJoseph Chen struct list_head *node; 210483d0493SJoseph Chen const char *name; 211483d0493SJoseph Chen int ret; 212483d0493SJoseph Chen 213483d0493SJoseph Chen if (!bidram_has_init()) 214483d0493SJoseph Chen return -ENOSYS; 215483d0493SJoseph Chen 216483d0493SJoseph Chen if (id == MEMBLK_ID_BY_NAME) { 217483d0493SJoseph Chen if (!mem_name) { 218483d0493SJoseph Chen BIDRAM_E("NULL name for reserve bidram\n"); 219483d0493SJoseph Chen return -EINVAL; 220483d0493SJoseph Chen } else { 221483d0493SJoseph Chen name = mem_name; 222483d0493SJoseph Chen } 223483d0493SJoseph Chen } else { 224483d0493SJoseph Chen if (id > MEMBLK_ID_UNK && id < MEMBLK_ID_MAX) { 225483d0493SJoseph Chen attr = mem_attr[id]; 226483d0493SJoseph Chen name = attr.name; 227483d0493SJoseph Chen } else { 228483d0493SJoseph Chen BIDRAM_E("Unsupport memblk id %d for reserve bidram\n", id); 229483d0493SJoseph Chen return -EINVAL; 230483d0493SJoseph Chen } 231483d0493SJoseph Chen } 232483d0493SJoseph Chen 233483d0493SJoseph Chen if (!name) { 234483d0493SJoseph Chen BIDRAM_E("NULL name for reserved bidram\n"); 235483d0493SJoseph Chen return -EINVAL; 236483d0493SJoseph Chen } 237483d0493SJoseph Chen 238483d0493SJoseph Chen if (!size) 239483d0493SJoseph Chen return 0; 240483d0493SJoseph Chen 241483d0493SJoseph Chen /* Check overlap */ 242483d0493SJoseph Chen list_for_each(node, &bidram->reserved_head) { 243483d0493SJoseph Chen mem = list_entry(node, struct memblock, node); 244356575c3SJoseph Chen BIDRAM_D("Has reserved: %s 0x%08lx - 0x%08lx\n", 245483d0493SJoseph Chen mem->attr.name, (ulong)mem->base, 246483d0493SJoseph Chen (ulong)(mem->base + mem->size)); 247483d0493SJoseph Chen if (!strcmp(mem->attr.name, name)) { 248483d0493SJoseph Chen BIDRAM_E("Failed to double reserve for existence \"%s\"\n", name); 249483d0493SJoseph Chen return -EEXIST; 250483d0493SJoseph Chen } else if (bidram_is_overlap(mem->base, mem->size, base, size)) { 251483d0493SJoseph Chen BIDRAM_D("\"%s\" (0x%08lx - 0x%08lx) reserve is " 252483d0493SJoseph Chen "overlap with existence \"%s\" (0x%08lx - " 253483d0493SJoseph Chen "0x%08lx)\n", 254483d0493SJoseph Chen name, (ulong)base, (ulong)(base + size), mem->attr.name, 255483d0493SJoseph Chen (ulong)mem->base, (ulong)(mem->base + mem->size)); 256483d0493SJoseph Chen } 257483d0493SJoseph Chen } 258483d0493SJoseph Chen 259356575c3SJoseph Chen BIDRAM_D("Reserve: \"%s\" 0x%08lx - 0x%08lx\n", 260356575c3SJoseph Chen name, (ulong)base, (ulong)(base + size)); 261356575c3SJoseph Chen 262483d0493SJoseph Chen ret = lmb_reserve(&bidram->lmb, base, size); 263483d0493SJoseph Chen if (ret >= 0) { 264483d0493SJoseph Chen mem = malloc(sizeof(*mem)); 265483d0493SJoseph Chen if (!mem) { 266483d0493SJoseph Chen BIDRAM_E("No memory for \"%s\" reserve bidram\n", name); 267483d0493SJoseph Chen return -ENOMEM; 268483d0493SJoseph Chen } 269483d0493SJoseph Chen 270483d0493SJoseph Chen #ifdef CONFIG_SYSMEM 271483d0493SJoseph Chen /* Sync to sysmem */ 272483d0493SJoseph Chen if (sysmem_has_init()) { 273483d0493SJoseph Chen void *paddr; 274483d0493SJoseph Chen 275483d0493SJoseph Chen if (id == MEMBLK_ID_BY_NAME) 276483d0493SJoseph Chen paddr = sysmem_alloc_base_by_name(name, base, size); 277483d0493SJoseph Chen else 278483d0493SJoseph Chen paddr = sysmem_alloc_base(id, base, size); 279483d0493SJoseph Chen if (!paddr) { 280483d0493SJoseph Chen BIDRAM_E("Sync \"%s\" to sysmem failed\n", name); 281483d0493SJoseph Chen return -ENOMEM; 282483d0493SJoseph Chen } 283483d0493SJoseph Chen } 284483d0493SJoseph Chen #endif 285483d0493SJoseph Chen mem->base = base; 286483d0493SJoseph Chen mem->size = size; 287483d0493SJoseph Chen if (id == MEMBLK_ID_BY_NAME) { 288483d0493SJoseph Chen mem->attr.name = name; 289483d0493SJoseph Chen mem->attr.flags = 0; 290483d0493SJoseph Chen } else { 291483d0493SJoseph Chen mem->attr = attr; 292483d0493SJoseph Chen } 293483d0493SJoseph Chen list_add_tail(&mem->node, &bidram->reserved_head); 294483d0493SJoseph Chen } else { 295483d0493SJoseph Chen BIDRAM_E("Failed to reserve \"%s\" 0x%08lx - 0x%08lx\n", 296483d0493SJoseph Chen name, (ulong)base, (ulong)(base + size)); 297483d0493SJoseph Chen return -EINVAL; 298483d0493SJoseph Chen } 299483d0493SJoseph Chen 300483d0493SJoseph Chen return 0; 301483d0493SJoseph Chen } 302483d0493SJoseph Chen 303483d0493SJoseph Chen int bidram_reserve(enum memblk_id id, phys_addr_t base, phys_size_t size) 304483d0493SJoseph Chen { 305483d0493SJoseph Chen int ret; 306483d0493SJoseph Chen 307483d0493SJoseph Chen ret = bidram_core_reserve(id, NULL, base, size); 308483d0493SJoseph Chen if (!ret) 309483d0493SJoseph Chen bidram_gen_gd_bi_dram(); 310483d0493SJoseph Chen else 311483d0493SJoseph Chen bidram_dump(); 312483d0493SJoseph Chen 313483d0493SJoseph Chen return ret; 314483d0493SJoseph Chen } 315483d0493SJoseph Chen 316483d0493SJoseph Chen int bidram_reserve_by_name(const char *name, 317483d0493SJoseph Chen phys_addr_t base, phys_size_t size) 318483d0493SJoseph Chen { 319483d0493SJoseph Chen int ret; 320483d0493SJoseph Chen 321483d0493SJoseph Chen ret = bidram_core_reserve(MEMBLK_ID_BY_NAME, name, base, size); 322483d0493SJoseph Chen if (!ret) 323483d0493SJoseph Chen bidram_gen_gd_bi_dram(); 324483d0493SJoseph Chen else 325483d0493SJoseph Chen bidram_dump(); 326483d0493SJoseph Chen 327483d0493SJoseph Chen return ret; 328483d0493SJoseph Chen } 329483d0493SJoseph Chen 330483d0493SJoseph Chen int bidram_initr(void) 331483d0493SJoseph Chen { 332483d0493SJoseph Chen return !bidram_get_ram_size(); 333483d0493SJoseph Chen } 334483d0493SJoseph Chen 335483d0493SJoseph Chen phys_size_t bidram_get_ram_size(void) 336483d0493SJoseph Chen { 337483d0493SJoseph Chen struct bidram *bidram = &plat_bidram; 338483d0493SJoseph Chen struct memblock bad[MAX_BAD_MEMBLK]; 339483d0493SJoseph Chen struct memblock *list; 340483d0493SJoseph Chen phys_size_t ram_addr_end = CONFIG_SYS_SDRAM_BASE; 341483d0493SJoseph Chen phys_addr_t end_addr; 342483d0493SJoseph Chen parse_fn_t parse_fn; 343483d0493SJoseph Chen int i, count, ret; 344483d0493SJoseph Chen int bad_cnt = 0; 345483d0493SJoseph Chen char bad_name[12]; 346483d0493SJoseph Chen 347483d0493SJoseph Chen parse_fn = board_bidram_parse_fn(); 348483d0493SJoseph Chen if (!parse_fn) { 349483d0493SJoseph Chen BIDRAM_E("Can't find dram parse fn\n"); 350483d0493SJoseph Chen return 0; 351483d0493SJoseph Chen } 352483d0493SJoseph Chen 353483d0493SJoseph Chen list = parse_fn(&count); 354483d0493SJoseph Chen if (!list) { 355483d0493SJoseph Chen BIDRAM_E("Can't get dram banks\n"); 356483d0493SJoseph Chen return 0; 357483d0493SJoseph Chen } 358483d0493SJoseph Chen 359483d0493SJoseph Chen if (count > CONFIG_NR_DRAM_BANKS) { 360483d0493SJoseph Chen BIDRAM_E("Too many dram banks, %d is over max: %d\n", 361483d0493SJoseph Chen count, CONFIG_NR_DRAM_BANKS); 362483d0493SJoseph Chen return 0; 363483d0493SJoseph Chen } 364483d0493SJoseph Chen 365483d0493SJoseph Chen /* Initial plat_bidram */ 366483d0493SJoseph Chen lmb_init(&bidram->lmb); 367483d0493SJoseph Chen INIT_LIST_HEAD(&bidram->reserved_head); 368483d0493SJoseph Chen bidram->has_init = true; 369483d0493SJoseph Chen 370483d0493SJoseph Chen /* Initial memory pool */ 371483d0493SJoseph Chen for (i = 0; i < count; i++) { 372483d0493SJoseph Chen BIDRAM_D("Add bank[%d] start=0x%08lx, end=0x%08lx\n", 373483d0493SJoseph Chen i, (ulong)list[i].base, 374483d0493SJoseph Chen (ulong)list[i].base + (ulong)list[i].size); 375483d0493SJoseph Chen 376483d0493SJoseph Chen if (!list[i].size) 377483d0493SJoseph Chen continue; 378483d0493SJoseph Chen 379483d0493SJoseph Chen /* We assume the last block gives the ram addr end */ 380483d0493SJoseph Chen if (i == count - 1) { 381483d0493SJoseph Chen ram_addr_end = list[i].base + list[i].size; 382483d0493SJoseph Chen ret = bidram_add(CONFIG_SYS_SDRAM_BASE, 383483d0493SJoseph Chen ram_addr_end - CONFIG_SYS_SDRAM_BASE); 384483d0493SJoseph Chen if (ret) { 385483d0493SJoseph Chen BIDRAM_E("Failed to add bidram from bi_dram[%d]\n", i); 386483d0493SJoseph Chen return 0; 387483d0493SJoseph Chen } 388483d0493SJoseph Chen } 389483d0493SJoseph Chen 390483d0493SJoseph Chen /* This is a bad dram bank? record it */ 391483d0493SJoseph Chen if (i > 0) { 392483d0493SJoseph Chen end_addr = list[i - 1].base + list[i - 1].size; 393483d0493SJoseph Chen 394483d0493SJoseph Chen if (list[i].base != end_addr) { 395483d0493SJoseph Chen snprintf(bad_name, 12, "%s%d", "BAD_RAM.", i - 1); 396483d0493SJoseph Chen bad[bad_cnt].attr.name = strdup(bad_name); 397483d0493SJoseph Chen bad[bad_cnt].base = end_addr; 398483d0493SJoseph Chen bad[bad_cnt].size = list[i].base - end_addr; 399483d0493SJoseph Chen bad_cnt++; 400483d0493SJoseph Chen if (bad_cnt > MAX_BAD_MEMBLK) { 401483d0493SJoseph Chen BIDRAM_E("Too many bad memory blocks\n"); 402483d0493SJoseph Chen return 0; 403483d0493SJoseph Chen } 404483d0493SJoseph Chen } 405483d0493SJoseph Chen } 406483d0493SJoseph Chen } 407483d0493SJoseph Chen 408483d0493SJoseph Chen /* Reserve bad dram bank after bidram_add(), treat as reserved region */ 409483d0493SJoseph Chen for (i = 0; i < bad_cnt; i++) { 410483d0493SJoseph Chen if (gd->flags & GD_FLG_RELOC) 411483d0493SJoseph Chen BIDRAM_R("Bad memblk%d: 0x%08lx - 0x%08lx\n", 412483d0493SJoseph Chen i, (ulong)bad[i].base, 413483d0493SJoseph Chen (ulong)bad[i].base + (ulong)bad[i].size); 414483d0493SJoseph Chen 415483d0493SJoseph Chen ret = bidram_reserve_by_name(bad[i].attr.name, 416483d0493SJoseph Chen bad[i].base, bad[i].size); 417483d0493SJoseph Chen if (ret) { 418483d0493SJoseph Chen BIDRAM_E("Failed to add bad memblk[%d]\n", i); 419483d0493SJoseph Chen return 0; 420483d0493SJoseph Chen } 421483d0493SJoseph Chen } 422483d0493SJoseph Chen 423483d0493SJoseph Chen /* Reserved for board */ 424483d0493SJoseph Chen ret = board_bidram_reserve(bidram); 425483d0493SJoseph Chen if (ret) { 426483d0493SJoseph Chen BIDRAM_E("Failed to reserve bidram for board\n"); 427483d0493SJoseph Chen return 0; 428483d0493SJoseph Chen } 429483d0493SJoseph Chen 430483d0493SJoseph Chen BIDRAM_D("DRAM size: 0x%08lx\n", 431483d0493SJoseph Chen (ulong)ram_addr_end - CONFIG_SYS_SDRAM_BASE); 432483d0493SJoseph Chen 433483d0493SJoseph Chen #ifdef DEBUG 434483d0493SJoseph Chen bidram_dump(); 435483d0493SJoseph Chen #endif 436483d0493SJoseph Chen 437483d0493SJoseph Chen return (ram_addr_end - CONFIG_SYS_SDRAM_BASE); 438483d0493SJoseph Chen } 439483d0493SJoseph Chen 440483d0493SJoseph Chen __weak parse_fn_t board_bidram_parse_fn(void) 441483d0493SJoseph Chen { 442483d0493SJoseph Chen /* please define platform specific board_bidram_parse_fn() */ 443483d0493SJoseph Chen return NULL; 444483d0493SJoseph Chen } 445483d0493SJoseph Chen 446483d0493SJoseph Chen __weak int board_bidram_reserve(struct bidram *bidram) 447483d0493SJoseph Chen { 448483d0493SJoseph Chen /* please define platform specific board_bidram_reserve() */ 449483d0493SJoseph Chen return 0; 450483d0493SJoseph Chen } 451483d0493SJoseph Chen 452483d0493SJoseph Chen static int do_dump_bidram(cmd_tbl_t *cmdtp, int flag, 453483d0493SJoseph Chen int argc, char *const argv[]) 454483d0493SJoseph Chen { 455483d0493SJoseph Chen bidram_dump(); 456483d0493SJoseph Chen return 0; 457483d0493SJoseph Chen } 458483d0493SJoseph Chen 459483d0493SJoseph Chen U_BOOT_CMD( 460483d0493SJoseph Chen dump_bidram, 1, 1, do_dump_bidram, 461483d0493SJoseph Chen "Dump bidram layout", 462483d0493SJoseph Chen "" 463483d0493SJoseph Chen ); 464