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 { 122*1d09cf29SJoseph Chen struct bidram *bidram = &plat_bidram; 123483d0493SJoseph Chen struct lmb *lmb = &plat_bidram.lmb; 124483d0493SJoseph Chen struct lmb_property *mem_rgn = lmb->memory.region; 125483d0493SJoseph Chen struct lmb_property *res_rgn = lmb->reserved.region; 126483d0493SJoseph Chen int rsv_cnt = lmb->reserved.cnt; 127483d0493SJoseph Chen int i, idx = 0; 128483d0493SJoseph Chen 129483d0493SJoseph Chen if (!gd || !gd->bd) { 130483d0493SJoseph Chen BIDRAM_D("Ignore bi dram bank update\n"); 131483d0493SJoseph Chen return; 132483d0493SJoseph Chen } 133483d0493SJoseph Chen 134356575c3SJoseph Chen /* 135356575c3SJoseph Chen * LBM default init: 136356575c3SJoseph Chen * lmb->reserved.cnt = 1; 137356575c3SJoseph Chen * lmb->reserved.region[0].base = 0; 138356575c3SJoseph Chen * lmb->reserved.region[0].size = 0; 139356575c3SJoseph Chen * 140356575c3SJoseph Chen * Here handle that: there is the only one dram bank available. 141356575c3SJoseph Chen */ 142356575c3SJoseph Chen if (rsv_cnt == 1 && !res_rgn[0].base && !res_rgn[0].size) { 143356575c3SJoseph Chen gd->bd->bi_dram[0].start = mem_rgn[0].base; 144356575c3SJoseph Chen gd->bd->bi_dram[0].size = mem_rgn[0].size; 145356575c3SJoseph Chen goto done; 146356575c3SJoseph Chen } 147356575c3SJoseph Chen 148483d0493SJoseph Chen /* If reserved rgn is not from sdram start */ 149483d0493SJoseph Chen if (res_rgn[0].base != mem_rgn[0].base) { 150483d0493SJoseph Chen gd->bd->bi_dram[idx].start = mem_rgn[0].base; 151483d0493SJoseph Chen gd->bd->bi_dram[idx].size = res_rgn[0].base - 152483d0493SJoseph Chen gd->bd->bi_dram[idx].start; 153483d0493SJoseph Chen idx++; 154483d0493SJoseph Chen } 155483d0493SJoseph Chen 156483d0493SJoseph Chen /* 157483d0493SJoseph Chen * Note: If reserved rgn is not from sdram start, idx=1 now, otherwise 0. 158483d0493SJoseph Chen */ 159483d0493SJoseph Chen for (i = 0; i < rsv_cnt; i++, idx++) { 160483d0493SJoseph Chen if (res_rgn[i].base + res_rgn[i].size >= gd->ram_top) 161483d0493SJoseph Chen goto done; 162483d0493SJoseph Chen 163483d0493SJoseph Chen gd->bd->bi_dram[idx].start = res_rgn[i].base + res_rgn[i].size; 164483d0493SJoseph Chen if (i + 1 < rsv_cnt) 165483d0493SJoseph Chen gd->bd->bi_dram[idx].size = res_rgn[i + 1].base - 166483d0493SJoseph Chen gd->bd->bi_dram[idx].start; 167483d0493SJoseph Chen else 168483d0493SJoseph Chen gd->bd->bi_dram[idx].size = gd->ram_top - 169483d0493SJoseph Chen gd->bd->bi_dram[idx].start; 170483d0493SJoseph Chen } 171483d0493SJoseph Chen done: 172*1d09cf29SJoseph Chen /* Append 4GB+ memory blocks */ 173*1d09cf29SJoseph Chen if (bidram->fixup) { 174*1d09cf29SJoseph Chen for (i = 0; i < MEM_RESV_COUNT; i++) { 175*1d09cf29SJoseph Chen if (!bidram->size_u64[i]) 176*1d09cf29SJoseph Chen continue; 177*1d09cf29SJoseph Chen gd->bd->bi_dram[idx].start = bidram->base_u64[i]; 178*1d09cf29SJoseph Chen gd->bd->bi_dram[idx].size = bidram->size_u64[i]; 179*1d09cf29SJoseph Chen BIDRAM_D("FIXUP: gd->bi_dram[%d]: start=0x%llx, size=0x%llx\n", 180*1d09cf29SJoseph Chen idx, bidram->base_u64[i], bidram->size_u64[i]); 181*1d09cf29SJoseph Chen idx++; 182483d0493SJoseph Chen } 183483d0493SJoseph Chen } 184483d0493SJoseph Chen 185*1d09cf29SJoseph Chen for (i = 0; i < idx; i++) { 186*1d09cf29SJoseph Chen BIDRAM_D("GEN: gd->bi_dram[%d]: start=0x%llx, end=0x%llx\n", 187*1d09cf29SJoseph Chen i, (u64)gd->bd->bi_dram[i].start, 188*1d09cf29SJoseph Chen (u64)gd->bd->bi_dram[i].start + 189*1d09cf29SJoseph Chen (u64)gd->bd->bi_dram[i].size); 190*1d09cf29SJoseph Chen } 191*1d09cf29SJoseph Chen } 192*1d09cf29SJoseph Chen 193*1d09cf29SJoseph Chen int bidram_fixup(void) 194*1d09cf29SJoseph Chen { 195*1d09cf29SJoseph Chen struct bidram *bidram = &plat_bidram; 196*1d09cf29SJoseph Chen 197*1d09cf29SJoseph Chen bidram->fixup = true; 198*1d09cf29SJoseph Chen bidram_gen_gd_bi_dram(); 199*1d09cf29SJoseph Chen 200*1d09cf29SJoseph Chen return 0; 201*1d09cf29SJoseph Chen } 202*1d09cf29SJoseph Chen 203*1d09cf29SJoseph Chen u64 bidram_append_size(void) 204*1d09cf29SJoseph Chen { 205*1d09cf29SJoseph Chen struct bidram *bidram = &plat_bidram; 206*1d09cf29SJoseph Chen u64 size = 0; 207*1d09cf29SJoseph Chen int i; 208*1d09cf29SJoseph Chen 209*1d09cf29SJoseph Chen /* 4GB+ */ 210*1d09cf29SJoseph Chen for (i = 0; i < MEM_RESV_COUNT; i++) 211*1d09cf29SJoseph Chen size += bidram->size_u64[i]; 212*1d09cf29SJoseph Chen 213*1d09cf29SJoseph Chen return size; 214*1d09cf29SJoseph Chen } 215*1d09cf29SJoseph Chen 216483d0493SJoseph Chen static int bidram_is_overlap(phys_addr_t base1, phys_size_t size1, 217483d0493SJoseph Chen phys_addr_t base2, phys_size_t size2) 218483d0493SJoseph Chen { 219483d0493SJoseph Chen return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); 220483d0493SJoseph Chen } 221483d0493SJoseph Chen 222fc7ff0f0SJoseph Chen struct memblock *bidram_reserved_is_overlap(phys_addr_t base, phys_size_t size) 223fc7ff0f0SJoseph Chen { 224fc7ff0f0SJoseph Chen struct bidram *bidram = &plat_bidram; 225fc7ff0f0SJoseph Chen struct list_head *node; 226fc7ff0f0SJoseph Chen struct memblock *mem; 227fc7ff0f0SJoseph Chen 228fc7ff0f0SJoseph Chen if (!bidram_has_init()) 229fc7ff0f0SJoseph Chen return false; 230fc7ff0f0SJoseph Chen 231fc7ff0f0SJoseph Chen list_for_each(node, &bidram->reserved_head) { 232fc7ff0f0SJoseph Chen mem = list_entry(node, struct memblock, node); 233fc7ff0f0SJoseph Chen if (bidram_is_overlap(mem->base, mem->size, base, size)) 234fc7ff0f0SJoseph Chen return mem; 235fc7ff0f0SJoseph Chen } 236fc7ff0f0SJoseph Chen 237fc7ff0f0SJoseph Chen return NULL; 238fc7ff0f0SJoseph Chen } 239fc7ff0f0SJoseph Chen 240483d0493SJoseph Chen static int bidram_core_reserve(enum memblk_id id, const char *mem_name, 241483d0493SJoseph Chen phys_addr_t base, phys_size_t size) 242483d0493SJoseph Chen { 243483d0493SJoseph Chen struct bidram *bidram = &plat_bidram; 244483d0493SJoseph Chen struct memblk_attr attr; 245483d0493SJoseph Chen struct memblock *mem; 246483d0493SJoseph Chen struct list_head *node; 247483d0493SJoseph Chen const char *name; 248483d0493SJoseph Chen int ret; 249483d0493SJoseph Chen 250483d0493SJoseph Chen if (!bidram_has_init()) 251483d0493SJoseph Chen return -ENOSYS; 252483d0493SJoseph Chen 253483d0493SJoseph Chen if (id == MEMBLK_ID_BY_NAME) { 254483d0493SJoseph Chen if (!mem_name) { 255483d0493SJoseph Chen BIDRAM_E("NULL name for reserve bidram\n"); 256483d0493SJoseph Chen return -EINVAL; 257483d0493SJoseph Chen } else { 258483d0493SJoseph Chen name = mem_name; 259483d0493SJoseph Chen } 260483d0493SJoseph Chen } else { 261483d0493SJoseph Chen if (id > MEMBLK_ID_UNK && id < MEMBLK_ID_MAX) { 262483d0493SJoseph Chen attr = mem_attr[id]; 263483d0493SJoseph Chen name = attr.name; 264483d0493SJoseph Chen } else { 265483d0493SJoseph Chen BIDRAM_E("Unsupport memblk id %d for reserve bidram\n", id); 266483d0493SJoseph Chen return -EINVAL; 267483d0493SJoseph Chen } 268483d0493SJoseph Chen } 269483d0493SJoseph Chen 270483d0493SJoseph Chen if (!name) { 271483d0493SJoseph Chen BIDRAM_E("NULL name for reserved bidram\n"); 272483d0493SJoseph Chen return -EINVAL; 273483d0493SJoseph Chen } 274483d0493SJoseph Chen 275483d0493SJoseph Chen if (!size) 276483d0493SJoseph Chen return 0; 277483d0493SJoseph Chen 278483d0493SJoseph Chen /* Check overlap */ 279483d0493SJoseph Chen list_for_each(node, &bidram->reserved_head) { 280483d0493SJoseph Chen mem = list_entry(node, struct memblock, node); 281356575c3SJoseph Chen BIDRAM_D("Has reserved: %s 0x%08lx - 0x%08lx\n", 282483d0493SJoseph Chen mem->attr.name, (ulong)mem->base, 283483d0493SJoseph Chen (ulong)(mem->base + mem->size)); 284483d0493SJoseph Chen if (!strcmp(mem->attr.name, name)) { 285483d0493SJoseph Chen BIDRAM_E("Failed to double reserve for existence \"%s\"\n", name); 286483d0493SJoseph Chen return -EEXIST; 287483d0493SJoseph Chen } else if (bidram_is_overlap(mem->base, mem->size, base, size)) { 288483d0493SJoseph Chen BIDRAM_D("\"%s\" (0x%08lx - 0x%08lx) reserve is " 289483d0493SJoseph Chen "overlap with existence \"%s\" (0x%08lx - " 290483d0493SJoseph Chen "0x%08lx)\n", 291483d0493SJoseph Chen name, (ulong)base, (ulong)(base + size), mem->attr.name, 292483d0493SJoseph Chen (ulong)mem->base, (ulong)(mem->base + mem->size)); 293483d0493SJoseph Chen } 294483d0493SJoseph Chen } 295483d0493SJoseph Chen 296356575c3SJoseph Chen BIDRAM_D("Reserve: \"%s\" 0x%08lx - 0x%08lx\n", 297356575c3SJoseph Chen name, (ulong)base, (ulong)(base + size)); 298356575c3SJoseph Chen 299483d0493SJoseph Chen ret = lmb_reserve(&bidram->lmb, base, size); 300483d0493SJoseph Chen if (ret >= 0) { 301483d0493SJoseph Chen mem = malloc(sizeof(*mem)); 302483d0493SJoseph Chen if (!mem) { 303483d0493SJoseph Chen BIDRAM_E("No memory for \"%s\" reserve bidram\n", name); 304483d0493SJoseph Chen return -ENOMEM; 305483d0493SJoseph Chen } 306483d0493SJoseph Chen 307483d0493SJoseph Chen #ifdef CONFIG_SYSMEM 308483d0493SJoseph Chen /* Sync to sysmem */ 309483d0493SJoseph Chen if (sysmem_has_init()) { 310483d0493SJoseph Chen void *paddr; 311483d0493SJoseph Chen 312483d0493SJoseph Chen if (id == MEMBLK_ID_BY_NAME) 313483d0493SJoseph Chen paddr = sysmem_alloc_base_by_name(name, base, size); 314483d0493SJoseph Chen else 315483d0493SJoseph Chen paddr = sysmem_alloc_base(id, base, size); 316483d0493SJoseph Chen if (!paddr) { 317483d0493SJoseph Chen BIDRAM_E("Sync \"%s\" to sysmem failed\n", name); 318483d0493SJoseph Chen return -ENOMEM; 319483d0493SJoseph Chen } 320483d0493SJoseph Chen } 321483d0493SJoseph Chen #endif 322483d0493SJoseph Chen mem->base = base; 323483d0493SJoseph Chen mem->size = size; 324483d0493SJoseph Chen if (id == MEMBLK_ID_BY_NAME) { 325483d0493SJoseph Chen mem->attr.name = name; 326483d0493SJoseph Chen mem->attr.flags = 0; 327483d0493SJoseph Chen } else { 328483d0493SJoseph Chen mem->attr = attr; 329483d0493SJoseph Chen } 330483d0493SJoseph Chen list_add_tail(&mem->node, &bidram->reserved_head); 331483d0493SJoseph Chen } else { 332483d0493SJoseph Chen BIDRAM_E("Failed to reserve \"%s\" 0x%08lx - 0x%08lx\n", 333483d0493SJoseph Chen name, (ulong)base, (ulong)(base + size)); 334483d0493SJoseph Chen return -EINVAL; 335483d0493SJoseph Chen } 336483d0493SJoseph Chen 337483d0493SJoseph Chen return 0; 338483d0493SJoseph Chen } 339483d0493SJoseph Chen 340483d0493SJoseph Chen int bidram_reserve(enum memblk_id id, phys_addr_t base, phys_size_t size) 341483d0493SJoseph Chen { 342483d0493SJoseph Chen int ret; 343483d0493SJoseph Chen 344483d0493SJoseph Chen ret = bidram_core_reserve(id, NULL, base, size); 345483d0493SJoseph Chen if (!ret) 346483d0493SJoseph Chen bidram_gen_gd_bi_dram(); 347483d0493SJoseph Chen else 348483d0493SJoseph Chen bidram_dump(); 349483d0493SJoseph Chen 350483d0493SJoseph Chen return ret; 351483d0493SJoseph Chen } 352483d0493SJoseph Chen 353483d0493SJoseph Chen int bidram_reserve_by_name(const char *name, 354483d0493SJoseph Chen phys_addr_t base, phys_size_t size) 355483d0493SJoseph Chen { 356483d0493SJoseph Chen int ret; 357483d0493SJoseph Chen 358483d0493SJoseph Chen ret = bidram_core_reserve(MEMBLK_ID_BY_NAME, name, base, size); 359483d0493SJoseph Chen if (!ret) 360483d0493SJoseph Chen bidram_gen_gd_bi_dram(); 361483d0493SJoseph Chen else 362483d0493SJoseph Chen bidram_dump(); 363483d0493SJoseph Chen 364483d0493SJoseph Chen return ret; 365483d0493SJoseph Chen } 366483d0493SJoseph Chen 367483d0493SJoseph Chen int bidram_initr(void) 368483d0493SJoseph Chen { 369483d0493SJoseph Chen return !bidram_get_ram_size(); 370483d0493SJoseph Chen } 371483d0493SJoseph Chen 372483d0493SJoseph Chen phys_size_t bidram_get_ram_size(void) 373483d0493SJoseph Chen { 374483d0493SJoseph Chen struct bidram *bidram = &plat_bidram; 375483d0493SJoseph Chen struct memblock bad[MAX_BAD_MEMBLK]; 376483d0493SJoseph Chen struct memblock *list; 377483d0493SJoseph Chen phys_size_t ram_addr_end = CONFIG_SYS_SDRAM_BASE; 378483d0493SJoseph Chen phys_addr_t end_addr; 379483d0493SJoseph Chen parse_fn_t parse_fn; 380483d0493SJoseph Chen int i, count, ret; 381*1d09cf29SJoseph Chen int bad_cnt = 0, n = 0; 382483d0493SJoseph Chen char bad_name[12]; 383483d0493SJoseph Chen 384483d0493SJoseph Chen parse_fn = board_bidram_parse_fn(); 385483d0493SJoseph Chen if (!parse_fn) { 386483d0493SJoseph Chen BIDRAM_E("Can't find dram parse fn\n"); 387483d0493SJoseph Chen return 0; 388483d0493SJoseph Chen } 389483d0493SJoseph Chen 390483d0493SJoseph Chen list = parse_fn(&count); 391483d0493SJoseph Chen if (!list) { 392483d0493SJoseph Chen BIDRAM_E("Can't get dram banks\n"); 393483d0493SJoseph Chen return 0; 394483d0493SJoseph Chen } 395483d0493SJoseph Chen 396483d0493SJoseph Chen if (count > CONFIG_NR_DRAM_BANKS) { 397483d0493SJoseph Chen BIDRAM_E("Too many dram banks, %d is over max: %d\n", 398483d0493SJoseph Chen count, CONFIG_NR_DRAM_BANKS); 399483d0493SJoseph Chen return 0; 400483d0493SJoseph Chen } 401483d0493SJoseph Chen 402483d0493SJoseph Chen /* Initial plat_bidram */ 403483d0493SJoseph Chen lmb_init(&bidram->lmb); 404483d0493SJoseph Chen INIT_LIST_HEAD(&bidram->reserved_head); 405483d0493SJoseph Chen bidram->has_init = true; 406483d0493SJoseph Chen 407483d0493SJoseph Chen /* Initial memory pool */ 408483d0493SJoseph Chen for (i = 0; i < count; i++) { 409483d0493SJoseph Chen BIDRAM_D("Add bank[%d] start=0x%08lx, end=0x%08lx\n", 410483d0493SJoseph Chen i, (ulong)list[i].base, 411483d0493SJoseph Chen (ulong)list[i].base + (ulong)list[i].size); 412483d0493SJoseph Chen 413*1d09cf29SJoseph Chen if (!list[i].size) { 414*1d09cf29SJoseph Chen /* handle 4GB+ */ 415*1d09cf29SJoseph Chen if (list[i].size_u64 && n < MEM_RESV_COUNT) { 416*1d09cf29SJoseph Chen bidram->base_u64[n] = list[i].base_u64; 417*1d09cf29SJoseph Chen bidram->size_u64[n] = list[i].size_u64; 418*1d09cf29SJoseph Chen n++; 419*1d09cf29SJoseph Chen } 420483d0493SJoseph Chen continue; 421*1d09cf29SJoseph Chen } 422483d0493SJoseph Chen 423483d0493SJoseph Chen /* We assume the last block gives the ram addr end */ 424483d0493SJoseph Chen ram_addr_end = list[i].base + list[i].size; 425483d0493SJoseph Chen 426483d0493SJoseph Chen /* This is a bad dram bank? record it */ 427483d0493SJoseph Chen if (i > 0) { 428483d0493SJoseph Chen end_addr = list[i - 1].base + list[i - 1].size; 429483d0493SJoseph Chen 430483d0493SJoseph Chen if (list[i].base != end_addr) { 431483d0493SJoseph Chen snprintf(bad_name, 12, "%s%d", "BAD_RAM.", i - 1); 432483d0493SJoseph Chen bad[bad_cnt].attr.name = strdup(bad_name); 433483d0493SJoseph Chen bad[bad_cnt].base = end_addr; 434483d0493SJoseph Chen bad[bad_cnt].size = list[i].base - end_addr; 435483d0493SJoseph Chen bad_cnt++; 436483d0493SJoseph Chen if (bad_cnt > MAX_BAD_MEMBLK) { 437483d0493SJoseph Chen BIDRAM_E("Too many bad memory blocks\n"); 438483d0493SJoseph Chen return 0; 439483d0493SJoseph Chen } 440483d0493SJoseph Chen } 441483d0493SJoseph Chen } 442483d0493SJoseph Chen } 443483d0493SJoseph Chen 444*1d09cf29SJoseph Chen ret = bidram_add(CONFIG_SYS_SDRAM_BASE, 445*1d09cf29SJoseph Chen ram_addr_end - CONFIG_SYS_SDRAM_BASE); 446*1d09cf29SJoseph Chen if (ret) { 447*1d09cf29SJoseph Chen BIDRAM_E("Failed to add bidram from bi_dram[%d]\n", i); 448*1d09cf29SJoseph Chen return 0; 449*1d09cf29SJoseph Chen } 450*1d09cf29SJoseph Chen 451483d0493SJoseph Chen /* Reserve bad dram bank after bidram_add(), treat as reserved region */ 452483d0493SJoseph Chen for (i = 0; i < bad_cnt; i++) { 453483d0493SJoseph Chen if (gd->flags & GD_FLG_RELOC) 454483d0493SJoseph Chen BIDRAM_R("Bad memblk%d: 0x%08lx - 0x%08lx\n", 455483d0493SJoseph Chen i, (ulong)bad[i].base, 456483d0493SJoseph Chen (ulong)bad[i].base + (ulong)bad[i].size); 457483d0493SJoseph Chen 458483d0493SJoseph Chen ret = bidram_reserve_by_name(bad[i].attr.name, 459483d0493SJoseph Chen bad[i].base, bad[i].size); 460483d0493SJoseph Chen if (ret) { 461483d0493SJoseph Chen BIDRAM_E("Failed to add bad memblk[%d]\n", i); 462483d0493SJoseph Chen return 0; 463483d0493SJoseph Chen } 464483d0493SJoseph Chen } 465483d0493SJoseph Chen 466483d0493SJoseph Chen /* Reserved for board */ 467483d0493SJoseph Chen ret = board_bidram_reserve(bidram); 468483d0493SJoseph Chen if (ret) { 469483d0493SJoseph Chen BIDRAM_E("Failed to reserve bidram for board\n"); 470483d0493SJoseph Chen return 0; 471483d0493SJoseph Chen } 472483d0493SJoseph Chen 473483d0493SJoseph Chen BIDRAM_D("DRAM size: 0x%08lx\n", 474483d0493SJoseph Chen (ulong)ram_addr_end - CONFIG_SYS_SDRAM_BASE); 475483d0493SJoseph Chen 476483d0493SJoseph Chen #ifdef DEBUG 477483d0493SJoseph Chen bidram_dump(); 478483d0493SJoseph Chen #endif 479483d0493SJoseph Chen 480483d0493SJoseph Chen return (ram_addr_end - CONFIG_SYS_SDRAM_BASE); 481483d0493SJoseph Chen } 482483d0493SJoseph Chen 483483d0493SJoseph Chen __weak parse_fn_t board_bidram_parse_fn(void) 484483d0493SJoseph Chen { 485483d0493SJoseph Chen /* please define platform specific board_bidram_parse_fn() */ 486483d0493SJoseph Chen return NULL; 487483d0493SJoseph Chen } 488483d0493SJoseph Chen 489483d0493SJoseph Chen __weak int board_bidram_reserve(struct bidram *bidram) 490483d0493SJoseph Chen { 491483d0493SJoseph Chen /* please define platform specific board_bidram_reserve() */ 492483d0493SJoseph Chen return 0; 493483d0493SJoseph Chen } 494483d0493SJoseph Chen 495483d0493SJoseph Chen static int do_dump_bidram(cmd_tbl_t *cmdtp, int flag, 496483d0493SJoseph Chen int argc, char *const argv[]) 497483d0493SJoseph Chen { 498483d0493SJoseph Chen bidram_dump(); 499483d0493SJoseph Chen return 0; 500483d0493SJoseph Chen } 501483d0493SJoseph Chen 502483d0493SJoseph Chen U_BOOT_CMD( 503483d0493SJoseph Chen dump_bidram, 1, 1, do_dump_bidram, 504483d0493SJoseph Chen "Dump bidram layout", 505483d0493SJoseph Chen "" 506483d0493SJoseph Chen ); 507