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> 12d8e6f8d0SJoseph 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 26*82a88d5eSXuhui Lin __weak void board_bidram_fixup(void) 27*82a88d5eSXuhui Lin { 28*82a88d5eSXuhui Lin } 29*82a88d5eSXuhui Lin 30483d0493SJoseph Chen static int bidram_has_init(void) 31483d0493SJoseph Chen { 32483d0493SJoseph Chen if (!plat_bidram.has_init) { 33483d0493SJoseph Chen BIDRAM_E("Framework is not initialized\n"); 34483d0493SJoseph Chen return 0; 35483d0493SJoseph Chen } 36483d0493SJoseph Chen 37483d0493SJoseph Chen return 1; 38483d0493SJoseph Chen } 39483d0493SJoseph Chen 40483d0493SJoseph Chen void bidram_dump(void) 41483d0493SJoseph Chen { 42483d0493SJoseph Chen struct bidram *bidram = &plat_bidram; 43483d0493SJoseph Chen struct lmb *lmb = &bidram->lmb; 44483d0493SJoseph Chen struct memblock *mem; 45483d0493SJoseph Chen struct list_head *node; 46483d0493SJoseph Chen ulong memory_size = 0; 47483d0493SJoseph Chen ulong reserved_size = 0; 48483d0493SJoseph Chen ulong i; 49483d0493SJoseph Chen 50483d0493SJoseph Chen if (!bidram_has_init()) 51483d0493SJoseph Chen return; 52483d0493SJoseph Chen 53483d0493SJoseph Chen printf("\n\nbidram_dump_all:\n"); 54483d0493SJoseph Chen 55483d0493SJoseph Chen /* Memory pool */ 56483d0493SJoseph Chen printf(" --------------------------------------------------------------------\n"); 57483d0493SJoseph Chen for (i = 0; i < lmb->memory.cnt; i++) { 58483d0493SJoseph Chen memory_size += lmb->memory.region[i].size; 59483d0493SJoseph Chen printf(" memory.rgn[%ld].addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", i, 60483d0493SJoseph Chen (ulong)lmb->memory.region[i].base, 61483d0493SJoseph Chen (ulong)lmb->memory.region[i].base + 62483d0493SJoseph Chen (ulong)lmb->memory.region[i].size, 63483d0493SJoseph Chen (ulong)lmb->memory.region[i].size); 64483d0493SJoseph Chen } 65483d0493SJoseph Chen printf("\n memory.total = 0x%08lx (%ld MiB. %ld KiB)\n", 66483d0493SJoseph Chen (ulong)memory_size, 67483d0493SJoseph Chen SIZE_MB((ulong)memory_size), 68483d0493SJoseph Chen SIZE_KB((ulong)memory_size)); 69483d0493SJoseph Chen 70483d0493SJoseph Chen /* Reserved */ 71483d0493SJoseph Chen i = 0; 72483d0493SJoseph Chen printf(" --------------------------------------------------------------------\n"); 73483d0493SJoseph Chen list_for_each(node, &bidram->reserved_head) { 74483d0493SJoseph Chen mem = list_entry(node, struct memblock, node); 75483d0493SJoseph Chen reserved_size += mem->size; 76483d0493SJoseph Chen printf(" reserved.rgn[%ld].name = \"%s\"\n", i, mem->attr.name); 77483d0493SJoseph Chen printf(" .addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", 78483d0493SJoseph Chen (ulong)mem->base, (ulong)mem->base + (ulong)mem->size, 79483d0493SJoseph Chen (ulong)mem->size); 80483d0493SJoseph Chen i++; 81483d0493SJoseph Chen } 82483d0493SJoseph Chen printf("\n reserved.total = 0x%08lx (%ld MiB. %ld KiB)\n", 83483d0493SJoseph Chen (ulong)reserved_size, 84483d0493SJoseph Chen SIZE_MB((ulong)reserved_size), 85483d0493SJoseph Chen SIZE_KB((ulong)reserved_size)); 86483d0493SJoseph Chen 87483d0493SJoseph Chen /* LMB core reserved */ 88483d0493SJoseph Chen printf(" --------------------------------------------------------------------\n"); 89483d0493SJoseph Chen reserved_size = 0; 90483d0493SJoseph Chen for (i = 0; i < lmb->reserved.cnt; i++) { 91483d0493SJoseph Chen reserved_size += lmb->reserved.region[i].size; 92483d0493SJoseph Chen printf(" LMB.reserved[%ld].addr = 0x%08lx - 0x%08lx (size: 0x%08lx)\n", i, 93483d0493SJoseph Chen (ulong)lmb->reserved.region[i].base, 94483d0493SJoseph Chen (ulong)lmb->reserved.region[i].base + 95483d0493SJoseph Chen (ulong)lmb->reserved.region[i].size, 96483d0493SJoseph Chen (ulong)lmb->reserved.region[i].size); 97483d0493SJoseph Chen } 98483d0493SJoseph Chen 99483d0493SJoseph Chen printf("\n reserved.core.total = 0x%08lx (%ld MiB. %ld KiB)\n", 100483d0493SJoseph Chen (ulong)reserved_size, 101483d0493SJoseph Chen SIZE_MB((ulong)reserved_size), 102483d0493SJoseph Chen SIZE_KB((ulong)reserved_size)); 103483d0493SJoseph Chen printf(" --------------------------------------------------------------------\n\n"); 104483d0493SJoseph Chen } 105483d0493SJoseph Chen 106483d0493SJoseph Chen static int bidram_add(phys_addr_t base, phys_size_t size) 107483d0493SJoseph Chen { 108483d0493SJoseph Chen struct bidram *bidram = &plat_bidram; 109483d0493SJoseph Chen int ret; 110483d0493SJoseph Chen 111483d0493SJoseph Chen if (!bidram_has_init()) 112483d0493SJoseph Chen return -ENOSYS; 113483d0493SJoseph Chen 114483d0493SJoseph Chen if (!size) 115483d0493SJoseph Chen return -EINVAL; 116483d0493SJoseph Chen 117483d0493SJoseph Chen ret = lmb_add(&bidram->lmb, base, size); 118483d0493SJoseph Chen if (ret < 0) 119483d0493SJoseph Chen BIDRAM_E("Failed to add bidram at 0x%08lx - 0x%08lx\n", 120483d0493SJoseph Chen (ulong)base, (ulong)(base + size)); 121483d0493SJoseph Chen 122483d0493SJoseph Chen return (ret >= 0) ? 0 : ret; 123483d0493SJoseph Chen } 124483d0493SJoseph Chen 125483d0493SJoseph Chen void bidram_gen_gd_bi_dram(void) 126483d0493SJoseph Chen { 1271d09cf29SJoseph Chen struct bidram *bidram = &plat_bidram; 128483d0493SJoseph Chen struct lmb *lmb = &plat_bidram.lmb; 129483d0493SJoseph Chen struct lmb_property *mem_rgn = lmb->memory.region; 130483d0493SJoseph Chen struct lmb_property *res_rgn = lmb->reserved.region; 131483d0493SJoseph Chen int rsv_cnt = lmb->reserved.cnt; 132483d0493SJoseph Chen int i, idx = 0; 133483d0493SJoseph Chen 134483d0493SJoseph Chen if (!gd || !gd->bd) { 135483d0493SJoseph Chen BIDRAM_D("Ignore bi dram bank update\n"); 136483d0493SJoseph Chen return; 137483d0493SJoseph Chen } 138483d0493SJoseph Chen 139356575c3SJoseph Chen /* 140356575c3SJoseph Chen * LBM default init: 141356575c3SJoseph Chen * lmb->reserved.cnt = 1; 142356575c3SJoseph Chen * lmb->reserved.region[0].base = 0; 143356575c3SJoseph Chen * lmb->reserved.region[0].size = 0; 144356575c3SJoseph Chen * 145356575c3SJoseph Chen * Here handle that: there is the only one dram bank available. 146356575c3SJoseph Chen */ 147356575c3SJoseph Chen if (rsv_cnt == 1 && !res_rgn[0].base && !res_rgn[0].size) { 148d8e6f8d0SJoseph Chen gd->bd->bi_dram[idx].start = mem_rgn[0].base; 149d8e6f8d0SJoseph Chen gd->bd->bi_dram[idx].size = mem_rgn[0].size; 150d8e6f8d0SJoseph Chen idx++; 151356575c3SJoseph Chen goto done; 152356575c3SJoseph Chen } 153356575c3SJoseph Chen 154483d0493SJoseph Chen /* If reserved rgn is not from sdram start */ 155483d0493SJoseph Chen if (res_rgn[0].base != mem_rgn[0].base) { 156483d0493SJoseph Chen gd->bd->bi_dram[idx].start = mem_rgn[0].base; 157483d0493SJoseph Chen gd->bd->bi_dram[idx].size = res_rgn[0].base - 158483d0493SJoseph Chen gd->bd->bi_dram[idx].start; 159483d0493SJoseph Chen idx++; 160483d0493SJoseph Chen } 161483d0493SJoseph Chen 162483d0493SJoseph Chen /* 163483d0493SJoseph Chen * Note: If reserved rgn is not from sdram start, idx=1 now, otherwise 0. 164483d0493SJoseph Chen */ 165483d0493SJoseph Chen for (i = 0; i < rsv_cnt; i++, idx++) { 166483d0493SJoseph Chen if (res_rgn[i].base + res_rgn[i].size >= gd->ram_top) 167483d0493SJoseph Chen goto done; 168483d0493SJoseph Chen 169483d0493SJoseph Chen gd->bd->bi_dram[idx].start = res_rgn[i].base + res_rgn[i].size; 170483d0493SJoseph Chen if (i + 1 < rsv_cnt) 171483d0493SJoseph Chen gd->bd->bi_dram[idx].size = res_rgn[i + 1].base - 172483d0493SJoseph Chen gd->bd->bi_dram[idx].start; 173483d0493SJoseph Chen else 174483d0493SJoseph Chen gd->bd->bi_dram[idx].size = gd->ram_top - 175483d0493SJoseph Chen gd->bd->bi_dram[idx].start; 176483d0493SJoseph Chen } 177483d0493SJoseph Chen done: 178d8e6f8d0SJoseph Chen /* Append 4GB+ memory blocks and extend ram top */ 1791d09cf29SJoseph Chen if (bidram->fixup) { 180d8e6f8d0SJoseph Chen /* extend ram top */ 181d8e6f8d0SJoseph Chen if (gd->ram_top_ext_size) { 182d8e6f8d0SJoseph Chen int pos = idx - 1; 183d8e6f8d0SJoseph Chen ulong top; 184d8e6f8d0SJoseph Chen 185d8e6f8d0SJoseph Chen if (gd->bd->bi_dram[pos].start + 186d8e6f8d0SJoseph Chen gd->bd->bi_dram[pos].size == gd->ram_top) { 187d8e6f8d0SJoseph Chen top = gd->bd->bi_dram[pos].start + gd->bd->bi_dram[pos].size; 188d8e6f8d0SJoseph Chen gd->bd->bi_dram[pos].size += gd->ram_top_ext_size; 189d8e6f8d0SJoseph Chen printf("Extend top: 0x%08lx -> 0x%08lx\n", 190d8e6f8d0SJoseph Chen top, top + (ulong)gd->ram_top_ext_size); 191d8e6f8d0SJoseph Chen } 192d8e6f8d0SJoseph Chen } 193d8e6f8d0SJoseph Chen 194d8e6f8d0SJoseph Chen /* append 4GB+ */ 1951d09cf29SJoseph Chen for (i = 0; i < MEM_RESV_COUNT; i++) { 1961d09cf29SJoseph Chen if (!bidram->size_u64[i]) 1971d09cf29SJoseph Chen continue; 1981d09cf29SJoseph Chen gd->bd->bi_dram[idx].start = bidram->base_u64[i]; 1991d09cf29SJoseph Chen gd->bd->bi_dram[idx].size = bidram->size_u64[i]; 2001d09cf29SJoseph Chen BIDRAM_D("FIXUP: gd->bi_dram[%d]: start=0x%llx, size=0x%llx\n", 2011d09cf29SJoseph Chen idx, bidram->base_u64[i], bidram->size_u64[i]); 2021d09cf29SJoseph Chen idx++; 203483d0493SJoseph Chen } 204483d0493SJoseph Chen } 205483d0493SJoseph Chen 2061d09cf29SJoseph Chen for (i = 0; i < idx; i++) { 2071d09cf29SJoseph Chen BIDRAM_D("GEN: gd->bi_dram[%d]: start=0x%llx, end=0x%llx\n", 2081d09cf29SJoseph Chen i, (u64)gd->bd->bi_dram[i].start, 2091d09cf29SJoseph Chen (u64)gd->bd->bi_dram[i].start + 2101d09cf29SJoseph Chen (u64)gd->bd->bi_dram[i].size); 2111d09cf29SJoseph Chen } 2121d09cf29SJoseph Chen } 2131d09cf29SJoseph Chen 2141d09cf29SJoseph Chen int bidram_fixup(void) 2151d09cf29SJoseph Chen { 2161d09cf29SJoseph Chen struct bidram *bidram = &plat_bidram; 2171d09cf29SJoseph Chen 2181d09cf29SJoseph Chen bidram->fixup = true; 2191d09cf29SJoseph Chen bidram_gen_gd_bi_dram(); 2201d09cf29SJoseph Chen 221*82a88d5eSXuhui Lin board_bidram_fixup(); 222*82a88d5eSXuhui Lin 2231d09cf29SJoseph Chen return 0; 2241d09cf29SJoseph Chen } 2251d09cf29SJoseph Chen 2261d09cf29SJoseph Chen u64 bidram_append_size(void) 2271d09cf29SJoseph Chen { 2281d09cf29SJoseph Chen struct bidram *bidram = &plat_bidram; 2291d09cf29SJoseph Chen u64 size = 0; 2301d09cf29SJoseph Chen int i; 2311d09cf29SJoseph Chen 2321d09cf29SJoseph Chen /* 4GB+ */ 2331d09cf29SJoseph Chen for (i = 0; i < MEM_RESV_COUNT; i++) 2341d09cf29SJoseph Chen size += bidram->size_u64[i]; 2351d09cf29SJoseph Chen 236d8e6f8d0SJoseph Chen if (gd->ram_top_ext_size) 237d8e6f8d0SJoseph Chen size += gd->ram_top_ext_size; 238d8e6f8d0SJoseph Chen 2391d09cf29SJoseph Chen return size; 2401d09cf29SJoseph Chen } 2411d09cf29SJoseph Chen 242483d0493SJoseph Chen static int bidram_is_overlap(phys_addr_t base1, phys_size_t size1, 243483d0493SJoseph Chen phys_addr_t base2, phys_size_t size2) 244483d0493SJoseph Chen { 245483d0493SJoseph Chen return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); 246483d0493SJoseph Chen } 247483d0493SJoseph Chen 248fc7ff0f0SJoseph Chen struct memblock *bidram_reserved_is_overlap(phys_addr_t base, phys_size_t size) 249fc7ff0f0SJoseph Chen { 250fc7ff0f0SJoseph Chen struct bidram *bidram = &plat_bidram; 251fc7ff0f0SJoseph Chen struct list_head *node; 252fc7ff0f0SJoseph Chen struct memblock *mem; 253fc7ff0f0SJoseph Chen 254fc7ff0f0SJoseph Chen if (!bidram_has_init()) 255fc7ff0f0SJoseph Chen return false; 256fc7ff0f0SJoseph Chen 257fc7ff0f0SJoseph Chen list_for_each(node, &bidram->reserved_head) { 258fc7ff0f0SJoseph Chen mem = list_entry(node, struct memblock, node); 259fc7ff0f0SJoseph Chen if (bidram_is_overlap(mem->base, mem->size, base, size)) 260fc7ff0f0SJoseph Chen return mem; 261fc7ff0f0SJoseph Chen } 262fc7ff0f0SJoseph Chen 263fc7ff0f0SJoseph Chen return NULL; 264fc7ff0f0SJoseph Chen } 265fc7ff0f0SJoseph Chen 266483d0493SJoseph Chen static int bidram_core_reserve(enum memblk_id id, const char *mem_name, 267483d0493SJoseph Chen phys_addr_t base, phys_size_t size) 268483d0493SJoseph Chen { 269483d0493SJoseph Chen struct bidram *bidram = &plat_bidram; 270483d0493SJoseph Chen struct memblk_attr attr; 271483d0493SJoseph Chen struct memblock *mem; 272483d0493SJoseph Chen struct list_head *node; 273483d0493SJoseph Chen const char *name; 274483d0493SJoseph Chen int ret; 275483d0493SJoseph Chen 276483d0493SJoseph Chen if (!bidram_has_init()) 277483d0493SJoseph Chen return -ENOSYS; 278483d0493SJoseph Chen 279c01d4489SJoseph Chen if (id == MEM_BY_NAME) { 280483d0493SJoseph Chen if (!mem_name) { 281483d0493SJoseph Chen BIDRAM_E("NULL name for reserve bidram\n"); 282483d0493SJoseph Chen return -EINVAL; 283483d0493SJoseph Chen } else { 284483d0493SJoseph Chen name = mem_name; 285483d0493SJoseph Chen } 286483d0493SJoseph Chen } else { 287c01d4489SJoseph Chen if (id > MEM_UNK && id < MEM_MAX) { 288483d0493SJoseph Chen attr = mem_attr[id]; 289483d0493SJoseph Chen name = attr.name; 290483d0493SJoseph Chen } else { 291483d0493SJoseph Chen BIDRAM_E("Unsupport memblk id %d for reserve bidram\n", id); 292483d0493SJoseph Chen return -EINVAL; 293483d0493SJoseph Chen } 294483d0493SJoseph Chen } 295483d0493SJoseph Chen 296483d0493SJoseph Chen if (!name) { 297483d0493SJoseph Chen BIDRAM_E("NULL name for reserved bidram\n"); 298483d0493SJoseph Chen return -EINVAL; 299483d0493SJoseph Chen } 300483d0493SJoseph Chen 301483d0493SJoseph Chen if (!size) 302483d0493SJoseph Chen return 0; 303483d0493SJoseph Chen 304483d0493SJoseph Chen /* Check overlap */ 305483d0493SJoseph Chen list_for_each(node, &bidram->reserved_head) { 306483d0493SJoseph Chen mem = list_entry(node, struct memblock, node); 307356575c3SJoseph Chen BIDRAM_D("Has reserved: %s 0x%08lx - 0x%08lx\n", 308483d0493SJoseph Chen mem->attr.name, (ulong)mem->base, 309483d0493SJoseph Chen (ulong)(mem->base + mem->size)); 310483d0493SJoseph Chen if (!strcmp(mem->attr.name, name)) { 311483d0493SJoseph Chen BIDRAM_E("Failed to double reserve for existence \"%s\"\n", name); 312483d0493SJoseph Chen return -EEXIST; 313483d0493SJoseph Chen } else if (bidram_is_overlap(mem->base, mem->size, base, size)) { 314483d0493SJoseph Chen BIDRAM_D("\"%s\" (0x%08lx - 0x%08lx) reserve is " 315483d0493SJoseph Chen "overlap with existence \"%s\" (0x%08lx - " 316483d0493SJoseph Chen "0x%08lx)\n", 317483d0493SJoseph Chen name, (ulong)base, (ulong)(base + size), mem->attr.name, 318483d0493SJoseph Chen (ulong)mem->base, (ulong)(mem->base + mem->size)); 319483d0493SJoseph Chen } 320483d0493SJoseph Chen } 321483d0493SJoseph Chen 322356575c3SJoseph Chen BIDRAM_D("Reserve: \"%s\" 0x%08lx - 0x%08lx\n", 323356575c3SJoseph Chen name, (ulong)base, (ulong)(base + size)); 324356575c3SJoseph Chen 325483d0493SJoseph Chen ret = lmb_reserve(&bidram->lmb, base, size); 326483d0493SJoseph Chen if (ret >= 0) { 327483d0493SJoseph Chen mem = malloc(sizeof(*mem)); 328483d0493SJoseph Chen if (!mem) { 329483d0493SJoseph Chen BIDRAM_E("No memory for \"%s\" reserve bidram\n", name); 330483d0493SJoseph Chen return -ENOMEM; 331483d0493SJoseph Chen } 332483d0493SJoseph Chen 333483d0493SJoseph Chen #ifdef CONFIG_SYSMEM 334483d0493SJoseph Chen /* Sync to sysmem */ 335483d0493SJoseph Chen if (sysmem_has_init()) { 336483d0493SJoseph Chen void *paddr; 337483d0493SJoseph Chen 338c01d4489SJoseph Chen if (id == MEM_BY_NAME) 339483d0493SJoseph Chen paddr = sysmem_alloc_base_by_name(name, base, size); 340483d0493SJoseph Chen else 341483d0493SJoseph Chen paddr = sysmem_alloc_base(id, base, size); 342483d0493SJoseph Chen if (!paddr) { 343483d0493SJoseph Chen BIDRAM_E("Sync \"%s\" to sysmem failed\n", name); 344483d0493SJoseph Chen return -ENOMEM; 345483d0493SJoseph Chen } 346483d0493SJoseph Chen } 347483d0493SJoseph Chen #endif 348483d0493SJoseph Chen mem->base = base; 349483d0493SJoseph Chen mem->size = size; 350c01d4489SJoseph Chen if (id == MEM_BY_NAME) { 351483d0493SJoseph Chen mem->attr.name = name; 352483d0493SJoseph Chen mem->attr.flags = 0; 353483d0493SJoseph Chen } else { 354483d0493SJoseph Chen mem->attr = attr; 355483d0493SJoseph Chen } 356483d0493SJoseph Chen list_add_tail(&mem->node, &bidram->reserved_head); 357483d0493SJoseph Chen } else { 358483d0493SJoseph Chen BIDRAM_E("Failed to reserve \"%s\" 0x%08lx - 0x%08lx\n", 359483d0493SJoseph Chen name, (ulong)base, (ulong)(base + size)); 360483d0493SJoseph Chen return -EINVAL; 361483d0493SJoseph Chen } 362483d0493SJoseph Chen 363483d0493SJoseph Chen return 0; 364483d0493SJoseph Chen } 365483d0493SJoseph Chen 366483d0493SJoseph Chen int bidram_reserve(enum memblk_id id, phys_addr_t base, phys_size_t size) 367483d0493SJoseph Chen { 368483d0493SJoseph Chen int ret; 369483d0493SJoseph Chen 370483d0493SJoseph Chen ret = bidram_core_reserve(id, NULL, base, size); 371483d0493SJoseph Chen if (!ret) 372483d0493SJoseph Chen bidram_gen_gd_bi_dram(); 373483d0493SJoseph Chen else 374483d0493SJoseph Chen bidram_dump(); 375483d0493SJoseph Chen 376483d0493SJoseph Chen return ret; 377483d0493SJoseph Chen } 378483d0493SJoseph Chen 379483d0493SJoseph Chen int bidram_reserve_by_name(const char *name, 380483d0493SJoseph Chen phys_addr_t base, phys_size_t size) 381483d0493SJoseph Chen { 382483d0493SJoseph Chen int ret; 383483d0493SJoseph Chen 384c01d4489SJoseph Chen ret = bidram_core_reserve(MEM_BY_NAME, name, base, size); 385483d0493SJoseph Chen if (!ret) 386483d0493SJoseph Chen bidram_gen_gd_bi_dram(); 387483d0493SJoseph Chen else 388483d0493SJoseph Chen bidram_dump(); 389483d0493SJoseph Chen 390483d0493SJoseph Chen return ret; 391483d0493SJoseph Chen } 392483d0493SJoseph Chen 393483d0493SJoseph Chen int bidram_initr(void) 394483d0493SJoseph Chen { 395483d0493SJoseph Chen return !bidram_get_ram_size(); 396483d0493SJoseph Chen } 397483d0493SJoseph Chen 398483d0493SJoseph Chen phys_size_t bidram_get_ram_size(void) 399483d0493SJoseph Chen { 400483d0493SJoseph Chen struct bidram *bidram = &plat_bidram; 401483d0493SJoseph Chen struct memblock bad[MAX_BAD_MEMBLK]; 402483d0493SJoseph Chen struct memblock *list; 403483d0493SJoseph Chen phys_size_t ram_addr_end = CONFIG_SYS_SDRAM_BASE; 404483d0493SJoseph Chen phys_addr_t end_addr; 405483d0493SJoseph Chen parse_fn_t parse_fn; 406483d0493SJoseph Chen int i, count, ret; 4071d09cf29SJoseph Chen int bad_cnt = 0, n = 0; 408483d0493SJoseph Chen char bad_name[12]; 409483d0493SJoseph Chen 410483d0493SJoseph Chen parse_fn = board_bidram_parse_fn(); 411483d0493SJoseph Chen if (!parse_fn) { 412483d0493SJoseph Chen BIDRAM_E("Can't find dram parse fn\n"); 413483d0493SJoseph Chen return 0; 414483d0493SJoseph Chen } 415483d0493SJoseph Chen 416483d0493SJoseph Chen list = parse_fn(&count); 417483d0493SJoseph Chen if (!list) { 418483d0493SJoseph Chen BIDRAM_E("Can't get dram banks\n"); 419483d0493SJoseph Chen return 0; 420483d0493SJoseph Chen } 421483d0493SJoseph Chen 422483d0493SJoseph Chen if (count > CONFIG_NR_DRAM_BANKS) { 423483d0493SJoseph Chen BIDRAM_E("Too many dram banks, %d is over max: %d\n", 424483d0493SJoseph Chen count, CONFIG_NR_DRAM_BANKS); 425483d0493SJoseph Chen return 0; 426483d0493SJoseph Chen } 427483d0493SJoseph Chen 428483d0493SJoseph Chen /* Initial plat_bidram */ 429483d0493SJoseph Chen lmb_init(&bidram->lmb); 430483d0493SJoseph Chen INIT_LIST_HEAD(&bidram->reserved_head); 431483d0493SJoseph Chen bidram->has_init = true; 432483d0493SJoseph Chen 433483d0493SJoseph Chen /* Initial memory pool */ 434483d0493SJoseph Chen for (i = 0; i < count; i++) { 435483d0493SJoseph Chen BIDRAM_D("Add bank[%d] start=0x%08lx, end=0x%08lx\n", 436483d0493SJoseph Chen i, (ulong)list[i].base, 437483d0493SJoseph Chen (ulong)list[i].base + (ulong)list[i].size); 438483d0493SJoseph Chen 4391d09cf29SJoseph Chen if (!list[i].size) { 4401d09cf29SJoseph Chen /* handle 4GB+ */ 4411d09cf29SJoseph Chen if (list[i].size_u64 && n < MEM_RESV_COUNT) { 4421d09cf29SJoseph Chen bidram->base_u64[n] = list[i].base_u64; 4431d09cf29SJoseph Chen bidram->size_u64[n] = list[i].size_u64; 4441d09cf29SJoseph Chen n++; 4451d09cf29SJoseph Chen } 446483d0493SJoseph Chen continue; 4471d09cf29SJoseph Chen } 448483d0493SJoseph Chen 449483d0493SJoseph Chen /* We assume the last block gives the ram addr end */ 450483d0493SJoseph Chen ram_addr_end = list[i].base + list[i].size; 451483d0493SJoseph Chen 452483d0493SJoseph Chen /* This is a bad dram bank? record it */ 453483d0493SJoseph Chen if (i > 0) { 454483d0493SJoseph Chen end_addr = list[i - 1].base + list[i - 1].size; 455483d0493SJoseph Chen 456483d0493SJoseph Chen if (list[i].base != end_addr) { 457483d0493SJoseph Chen snprintf(bad_name, 12, "%s%d", "BAD_RAM.", i - 1); 458483d0493SJoseph Chen bad[bad_cnt].attr.name = strdup(bad_name); 459483d0493SJoseph Chen bad[bad_cnt].base = end_addr; 460483d0493SJoseph Chen bad[bad_cnt].size = list[i].base - end_addr; 461483d0493SJoseph Chen bad_cnt++; 462483d0493SJoseph Chen if (bad_cnt > MAX_BAD_MEMBLK) { 463483d0493SJoseph Chen BIDRAM_E("Too many bad memory blocks\n"); 464483d0493SJoseph Chen return 0; 465483d0493SJoseph Chen } 466483d0493SJoseph Chen } 467483d0493SJoseph Chen } 468483d0493SJoseph Chen } 469483d0493SJoseph Chen 4701d09cf29SJoseph Chen ret = bidram_add(CONFIG_SYS_SDRAM_BASE, 4711d09cf29SJoseph Chen ram_addr_end - CONFIG_SYS_SDRAM_BASE); 4721d09cf29SJoseph Chen if (ret) { 4731d09cf29SJoseph Chen BIDRAM_E("Failed to add bidram from bi_dram[%d]\n", i); 4741d09cf29SJoseph Chen return 0; 4751d09cf29SJoseph Chen } 4761d09cf29SJoseph Chen 477483d0493SJoseph Chen /* Reserve bad dram bank after bidram_add(), treat as reserved region */ 478483d0493SJoseph Chen for (i = 0; i < bad_cnt; i++) { 479483d0493SJoseph Chen if (gd->flags & GD_FLG_RELOC) 480483d0493SJoseph Chen BIDRAM_R("Bad memblk%d: 0x%08lx - 0x%08lx\n", 481483d0493SJoseph Chen i, (ulong)bad[i].base, 482483d0493SJoseph Chen (ulong)bad[i].base + (ulong)bad[i].size); 483483d0493SJoseph Chen 484483d0493SJoseph Chen ret = bidram_reserve_by_name(bad[i].attr.name, 485483d0493SJoseph Chen bad[i].base, bad[i].size); 486483d0493SJoseph Chen if (ret) { 487483d0493SJoseph Chen BIDRAM_E("Failed to add bad memblk[%d]\n", i); 488483d0493SJoseph Chen return 0; 489483d0493SJoseph Chen } 490483d0493SJoseph Chen } 491483d0493SJoseph Chen 492483d0493SJoseph Chen /* Reserved for board */ 493483d0493SJoseph Chen ret = board_bidram_reserve(bidram); 494483d0493SJoseph Chen if (ret) { 495483d0493SJoseph Chen BIDRAM_E("Failed to reserve bidram for board\n"); 496483d0493SJoseph Chen return 0; 497483d0493SJoseph Chen } 498483d0493SJoseph Chen 499483d0493SJoseph Chen BIDRAM_D("DRAM size: 0x%08lx\n", 500483d0493SJoseph Chen (ulong)ram_addr_end - CONFIG_SYS_SDRAM_BASE); 501483d0493SJoseph Chen 502483d0493SJoseph Chen #ifdef DEBUG 503483d0493SJoseph Chen bidram_dump(); 504483d0493SJoseph Chen #endif 505483d0493SJoseph Chen 506483d0493SJoseph Chen return (ram_addr_end - CONFIG_SYS_SDRAM_BASE); 507483d0493SJoseph Chen } 508483d0493SJoseph Chen 509483d0493SJoseph Chen __weak parse_fn_t board_bidram_parse_fn(void) 510483d0493SJoseph Chen { 511483d0493SJoseph Chen /* please define platform specific board_bidram_parse_fn() */ 512483d0493SJoseph Chen return NULL; 513483d0493SJoseph Chen } 514483d0493SJoseph Chen 515483d0493SJoseph Chen __weak int board_bidram_reserve(struct bidram *bidram) 516483d0493SJoseph Chen { 517483d0493SJoseph Chen /* please define platform specific board_bidram_reserve() */ 518483d0493SJoseph Chen return 0; 519483d0493SJoseph Chen } 520483d0493SJoseph Chen 5212fe84ae1SJoseph Chen static int do_bidram_dump(cmd_tbl_t *cmdtp, int flag, 522483d0493SJoseph Chen int argc, char *const argv[]) 523483d0493SJoseph Chen { 524483d0493SJoseph Chen bidram_dump(); 525483d0493SJoseph Chen return 0; 526483d0493SJoseph Chen } 527483d0493SJoseph Chen 528483d0493SJoseph Chen U_BOOT_CMD( 5292fe84ae1SJoseph Chen bidram_dump, 1, 1, do_bidram_dump, 530483d0493SJoseph Chen "Dump bidram layout", 531483d0493SJoseph Chen "" 532483d0493SJoseph Chen ); 533