]> Git Repo - J-u-boot.git/blob - common/memtop.c
Merge patch series "Fix device removal order for Apple dart iommu"
[J-u-boot.git] / common / memtop.c
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
14 struct region {
15         phys_addr_t base;
16         phys_size_t size;
17 };
18
19 struct mem_region {
20         struct region rgn[MEM_RGN_COUNT];
21         uint count;
22 };
23
24 static 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
42 static 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
53 static 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
98 static 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
107 static 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
124 static int 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
154 phys_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 }
This page took 0.03497 seconds and 4 git commands to generate.