"Das U-Boot" Source Tree
at master 171 lines 3.7 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c) 2024, Linaro Limited 4 */ 5 6#include <fdt_support.h> 7#include <fdtdec.h> 8#include <memtop.h> 9 10#include <asm/types.h> 11 12#define MEM_RGN_COUNT 16 13 14struct region { 15 phys_addr_t base; 16 phys_size_t size; 17}; 18 19struct mem_region { 20 struct region rgn[MEM_RGN_COUNT]; 21 uint count; 22}; 23 24static void add_mem_region(struct mem_region *mem_rgn, phys_addr_t base, 25 phys_size_t size) 26{ 27 long i; 28 29 for (i = mem_rgn->count; i >= 0; i--) { 30 if (i && base < mem_rgn->rgn[i - 1].base) { 31 mem_rgn->rgn[i] = mem_rgn->rgn[i - 1]; 32 } else { 33 mem_rgn->rgn[i].base = base; 34 mem_rgn->rgn[i].size = size; 35 break; 36 } 37 } 38 39 mem_rgn->count++; 40} 41 42static void mem_regions_init(struct mem_region *mem) 43{ 44 uint i; 45 46 mem->count = 0; 47 for (i = 0; i < MEM_RGN_COUNT; i++) { 48 mem->rgn[i].base = 0; 49 mem->rgn[i].size = 0; 50 } 51} 52 53static int fdt_add_reserved_regions(struct mem_region *free_mem, 54 struct mem_region *reserved_mem, 55 void *fdt_blob) 56{ 57 u64 addr, size; 58 int i, total, ret; 59 int nodeoffset, subnode; 60 struct fdt_resource res; 61 62 if (fdt_check_header(fdt_blob) != 0) 63 return -1; 64 65 /* process memreserve sections */ 66 total = fdt_num_mem_rsv(fdt_blob); 67 assert_noisy(total < MEM_RGN_COUNT); 68 for (i = 0; i < total; i++) { 69 if (fdt_get_mem_rsv(fdt_blob, i, &addr, &size) != 0) 70 continue; 71 add_mem_region(reserved_mem, addr, size); 72 } 73 74 i = 0; 75 /* process reserved-memory */ 76 nodeoffset = fdt_subnode_offset(fdt_blob, 0, "reserved-memory"); 77 if (nodeoffset >= 0) { 78 subnode = fdt_first_subnode(fdt_blob, nodeoffset); 79 while (subnode >= 0) { 80 /* check if this subnode has a reg property */ 81 ret = fdt_get_resource(fdt_blob, subnode, "reg", 0, 82 &res); 83 if (!ret && fdtdec_get_is_enabled(fdt_blob, subnode)) { 84 addr = res.start; 85 size = res.end - res.start + 1; 86 assert_noisy(i < MEM_RGN_COUNT); 87 add_mem_region(reserved_mem, addr, size); 88 } 89 90 subnode = fdt_next_subnode(fdt_blob, subnode); 91 ++i; 92 } 93 } 94 95 return 0; 96} 97 98static long addrs_overlap(phys_addr_t base1, phys_size_t size1, 99 phys_addr_t base2, phys_size_t size2) 100{ 101 const phys_addr_t base1_end = base1 + size1 - 1; 102 const phys_addr_t base2_end = base2 + size2 - 1; 103 104 return ((base1 <= base2_end) && (base2 <= base1_end)); 105} 106 107static long region_overlap_check(struct mem_region *mem_rgn, phys_addr_t base, 108 phys_size_t size) 109{ 110 unsigned long i; 111 struct region *rgn = mem_rgn->rgn; 112 113 for (i = 0; i < mem_rgn->count; i++) { 114 phys_addr_t rgnbase = rgn[i].base; 115 phys_size_t rgnsize = rgn[i].size; 116 117 if (addrs_overlap(base, size, rgnbase, rgnsize)) 118 break; 119 } 120 121 return (i < mem_rgn->count) ? i : -1; 122} 123 124static phys_addr_t find_ram_top(struct mem_region *free_mem, 125 struct mem_region *reserved_mem, phys_size_t size) 126{ 127 long i, rgn; 128 phys_addr_t base = 0; 129 phys_addr_t res_base; 130 131 for (i = free_mem->count - 1; i >= 0; i--) { 132 phys_addr_t rgnbase = free_mem->rgn[i].base; 133 phys_size_t rgnsize = free_mem->rgn[i].size; 134 135 if (rgnsize < size) 136 continue; 137 138 base = rgnbase + rgnsize - size; 139 while (base && rgnbase <= base) { 140 rgn = region_overlap_check(reserved_mem, base, size); 141 if (rgn < 0) 142 return base; 143 144 res_base = reserved_mem->rgn[rgn].base; 145 if (res_base < size) 146 break; 147 base = res_base - size; 148 } 149 } 150 151 return 0; 152} 153 154phys_addr_t get_mem_top(phys_addr_t ram_start, phys_size_t ram_size, 155 phys_size_t size, void *fdt) 156{ 157 int i; 158 struct mem_region free_mem; 159 struct mem_region reserved_mem; 160 161 mem_regions_init(&free_mem); 162 mem_regions_init(&reserved_mem); 163 164 add_mem_region(&free_mem, ram_start, ram_size); 165 166 i = fdt_add_reserved_regions(&free_mem, &reserved_mem, fdt); 167 if (i < 0) 168 return 0; 169 170 return find_ram_top(&free_mem, &reserved_mem, size); 171}