xref: /rk3399_rockchip-uboot/lib/sysmem.c (revision ffa8f8b76ea89ab65082d036dfb58c7fb136d861)
1*ffa8f8b7SJoseph Chen // SPDX-License-Identifier: GPL-2.0
2*ffa8f8b7SJoseph Chen /*
3*ffa8f8b7SJoseph Chen  * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
4*ffa8f8b7SJoseph Chen  */
5*ffa8f8b7SJoseph Chen 
6*ffa8f8b7SJoseph Chen #include <common.h>
7*ffa8f8b7SJoseph Chen #include <sysmem.h>
8*ffa8f8b7SJoseph Chen #include <lmb.h>
9*ffa8f8b7SJoseph Chen #include <malloc.h>
10*ffa8f8b7SJoseph Chen #include <asm/io.h>
11*ffa8f8b7SJoseph Chen 
12*ffa8f8b7SJoseph Chen DECLARE_GLOBAL_DATA_PTR;
13*ffa8f8b7SJoseph Chen 
14*ffa8f8b7SJoseph Chen #define SYSMEM_MAGIC		0x4D454D53	/* "SMEM" */
15*ffa8f8b7SJoseph Chen #define SYSMEM_ALLOC_ANYWHERE	0
16*ffa8f8b7SJoseph Chen #define SYSMEM_ALLOC_NO_ALIGN	1
17*ffa8f8b7SJoseph Chen 
18*ffa8f8b7SJoseph Chen #ifndef CONFIG_SYS_STACK_SIZE
19*ffa8f8b7SJoseph Chen #define CONFIG_SYS_STACK_SIZE	SZ_2M
20*ffa8f8b7SJoseph Chen #endif
21*ffa8f8b7SJoseph Chen 
22*ffa8f8b7SJoseph Chen #define SIZE_MB(len)		((len) >> 20)
23*ffa8f8b7SJoseph Chen #define SIZE_KB(len)		(((len) % (1 << 20)) >> 10)
24*ffa8f8b7SJoseph Chen 
25*ffa8f8b7SJoseph Chen #define SYSMEM_I(fmt, args...)	printf("Sysmem: "fmt, ##args)
26*ffa8f8b7SJoseph Chen #define SYSMEM_W(fmt, args...)	printf("Sysmem Warn: "fmt, ##args)
27*ffa8f8b7SJoseph Chen #define SYSMEM_E(fmt, args...)	printf("Sysmem Error: "fmt, ##args)
28*ffa8f8b7SJoseph Chen #define SYSMEM_D(fmt, args...)	 debug("Sysmem Debug: "fmt, ##args)
29*ffa8f8b7SJoseph Chen 
30*ffa8f8b7SJoseph Chen static struct sysmem plat_sysmem;	/* Global for platform */
31*ffa8f8b7SJoseph Chen 
32*ffa8f8b7SJoseph Chen struct sysmem_check {
33*ffa8f8b7SJoseph Chen 	uint32_t magic;
34*ffa8f8b7SJoseph Chen };
35*ffa8f8b7SJoseph Chen 
36*ffa8f8b7SJoseph Chen static int sysmem_has_init(void)
37*ffa8f8b7SJoseph Chen {
38*ffa8f8b7SJoseph Chen 	if (!plat_sysmem.has_init) {
39*ffa8f8b7SJoseph Chen 		SYSMEM_E("Framework is not initialized\n");
40*ffa8f8b7SJoseph Chen 		return 0;
41*ffa8f8b7SJoseph Chen 	}
42*ffa8f8b7SJoseph Chen 
43*ffa8f8b7SJoseph Chen 	return 1;
44*ffa8f8b7SJoseph Chen }
45*ffa8f8b7SJoseph Chen 
46*ffa8f8b7SJoseph Chen void sysmem_dump(void)
47*ffa8f8b7SJoseph Chen {
48*ffa8f8b7SJoseph Chen #ifdef DEBUG
49*ffa8f8b7SJoseph Chen 	struct sysmem *sysmem = &plat_sysmem;
50*ffa8f8b7SJoseph Chen 	struct lmb *lmb = &sysmem->lmb;
51*ffa8f8b7SJoseph Chen 	struct sysmem_property *prop;
52*ffa8f8b7SJoseph Chen 	struct sysmem_check *check;
53*ffa8f8b7SJoseph Chen 	struct list_head *node;
54*ffa8f8b7SJoseph Chen 	ulong memory_size = 0;
55*ffa8f8b7SJoseph Chen 	ulong reserved_size = 0;
56*ffa8f8b7SJoseph Chen 	ulong allocated_size = 0;
57*ffa8f8b7SJoseph Chen 	ulong i;
58*ffa8f8b7SJoseph Chen 
59*ffa8f8b7SJoseph Chen 	if (!sysmem_has_init())
60*ffa8f8b7SJoseph Chen 		return;
61*ffa8f8b7SJoseph Chen 
62*ffa8f8b7SJoseph Chen 	printf("\nsysmem_dump_all:\n");
63*ffa8f8b7SJoseph Chen 
64*ffa8f8b7SJoseph Chen 	/* Memory pool */
65*ffa8f8b7SJoseph Chen 	printf("    ------------------------------------------------------\n");
66*ffa8f8b7SJoseph Chen 	for (i = 0; i < lmb->memory.cnt; i++) {
67*ffa8f8b7SJoseph Chen 		memory_size += lmb->memory.region[i].size;
68*ffa8f8b7SJoseph Chen 		printf("    memory.rgn[%ld].base     = 0x%08lx\n", i,
69*ffa8f8b7SJoseph Chen 		       (ulong)lmb->memory.region[i].base);
70*ffa8f8b7SJoseph Chen 		printf("		 .size     = 0x%08lx\n",
71*ffa8f8b7SJoseph Chen 		       (ulong)lmb->memory.region[i].size);
72*ffa8f8b7SJoseph Chen 	}
73*ffa8f8b7SJoseph Chen 	printf("\n    memory.total	   = 0x%08lx (%ld MiB. %ld KiB)\n",
74*ffa8f8b7SJoseph Chen 	       (ulong)memory_size,
75*ffa8f8b7SJoseph Chen 	       SIZE_MB((ulong)memory_size),
76*ffa8f8b7SJoseph Chen 	       SIZE_KB((ulong)memory_size));
77*ffa8f8b7SJoseph Chen 
78*ffa8f8b7SJoseph Chen 	/* Reserved */
79*ffa8f8b7SJoseph Chen 	i = 0;
80*ffa8f8b7SJoseph Chen 	printf("    ------------------------------------------------------\n");
81*ffa8f8b7SJoseph Chen 	list_for_each(node, &sysmem->reserved_head) {
82*ffa8f8b7SJoseph Chen 		prop = list_entry(node, struct sysmem_property, node);
83*ffa8f8b7SJoseph Chen 		reserved_size += prop->size;
84*ffa8f8b7SJoseph Chen 		printf("    reserved.rgn[%ld].name   = \"%s\"\n", i, prop->name);
85*ffa8f8b7SJoseph Chen 		printf("		   .base   = 0x%08lx\n",
86*ffa8f8b7SJoseph Chen 		       (ulong)prop->base);
87*ffa8f8b7SJoseph Chen 		printf("		   .size   = 0x%08lx\n",
88*ffa8f8b7SJoseph Chen 		       (ulong)prop->size);
89*ffa8f8b7SJoseph Chen 		i++;
90*ffa8f8b7SJoseph Chen 	}
91*ffa8f8b7SJoseph Chen 	printf("\n    reserved.total	   = 0x%08lx (%ld MiB. %ld KiB)\n",
92*ffa8f8b7SJoseph Chen 	       (ulong)reserved_size,
93*ffa8f8b7SJoseph Chen 	       SIZE_MB((ulong)reserved_size),
94*ffa8f8b7SJoseph Chen 	       SIZE_KB((ulong)reserved_size));
95*ffa8f8b7SJoseph Chen 
96*ffa8f8b7SJoseph Chen 	/* Allocated */
97*ffa8f8b7SJoseph Chen 	i = 0;
98*ffa8f8b7SJoseph Chen 	printf("    ------------------------------------------------------\n");
99*ffa8f8b7SJoseph Chen 	list_for_each(node, &sysmem->allocated_head) {
100*ffa8f8b7SJoseph Chen 		prop = list_entry(node, struct sysmem_property, node);
101*ffa8f8b7SJoseph Chen 		allocated_size += prop->size;
102*ffa8f8b7SJoseph Chen 		check = (struct sysmem_check *)
103*ffa8f8b7SJoseph Chen 				(prop->base + prop->size - sizeof(*check));
104*ffa8f8b7SJoseph Chen 		printf("    allocated.rgn[%ld].name  = \"%s\"%s\n",
105*ffa8f8b7SJoseph Chen 		       i, prop->name,
106*ffa8f8b7SJoseph Chen 		       check->magic != SYSMEM_MAGIC ? "	(Overflow)" : "");
107*ffa8f8b7SJoseph Chen 		printf("		    .base  = 0x%08lx\n",
108*ffa8f8b7SJoseph Chen 		       (ulong)prop->base);
109*ffa8f8b7SJoseph Chen 		printf("		    .size  = 0x%08lx\n",
110*ffa8f8b7SJoseph Chen 		       (ulong)prop->size);
111*ffa8f8b7SJoseph Chen 		i++;
112*ffa8f8b7SJoseph Chen 	}
113*ffa8f8b7SJoseph Chen 	printf("\n    allocated.total	   = 0x%08lx (%ld MiB. %ld KiB)\n",
114*ffa8f8b7SJoseph Chen 	       (ulong)allocated_size,
115*ffa8f8b7SJoseph Chen 	       SIZE_MB((ulong)allocated_size),
116*ffa8f8b7SJoseph Chen 	       SIZE_KB((ulong)allocated_size));
117*ffa8f8b7SJoseph Chen 
118*ffa8f8b7SJoseph Chen 	/* LMB core reserved */
119*ffa8f8b7SJoseph Chen 	printf("    ------------------------------------------------------\n");
120*ffa8f8b7SJoseph Chen 	reserved_size = 0;
121*ffa8f8b7SJoseph Chen 	for (i = 0; i < lmb->reserved.cnt; i++) {
122*ffa8f8b7SJoseph Chen 		reserved_size += lmb->reserved.region[i].size;
123*ffa8f8b7SJoseph Chen 		printf("    LMB.reserved[%ld].base   = 0x%08lx\n", i,
124*ffa8f8b7SJoseph Chen 		       (ulong)lmb->reserved.region[i].base);
125*ffa8f8b7SJoseph Chen 		printf("		   .size   = 0x%08lx\n",
126*ffa8f8b7SJoseph Chen 		       (ulong)lmb->reserved.region[i].size);
127*ffa8f8b7SJoseph Chen 	}
128*ffa8f8b7SJoseph Chen 
129*ffa8f8b7SJoseph Chen 	printf("\n    reserved.core.total	   = 0x%08lx (%ld MiB. %ld KiB)\n",
130*ffa8f8b7SJoseph Chen 	       (ulong)reserved_size,
131*ffa8f8b7SJoseph Chen 	       SIZE_MB((ulong)reserved_size),
132*ffa8f8b7SJoseph Chen 	       SIZE_KB((ulong)reserved_size));
133*ffa8f8b7SJoseph Chen 	printf("    ------------------------------------------------------\n\n");
134*ffa8f8b7SJoseph Chen #endif
135*ffa8f8b7SJoseph Chen }
136*ffa8f8b7SJoseph Chen 
137*ffa8f8b7SJoseph Chen int sysmem_check(void)
138*ffa8f8b7SJoseph Chen {
139*ffa8f8b7SJoseph Chen 	struct sysmem *sysmem = &plat_sysmem;
140*ffa8f8b7SJoseph Chen 	struct sysmem_property *prop;
141*ffa8f8b7SJoseph Chen 	struct sysmem_check *check;
142*ffa8f8b7SJoseph Chen 	struct list_head *node;
143*ffa8f8b7SJoseph Chen 	int ret = 0;
144*ffa8f8b7SJoseph Chen 
145*ffa8f8b7SJoseph Chen 	if (!sysmem_has_init())
146*ffa8f8b7SJoseph Chen 		return -ENOSYS;
147*ffa8f8b7SJoseph Chen 
148*ffa8f8b7SJoseph Chen 	/* Check allocated */
149*ffa8f8b7SJoseph Chen 	list_for_each(node, &sysmem->allocated_head) {
150*ffa8f8b7SJoseph Chen 		prop = list_entry(node, struct sysmem_property, node);
151*ffa8f8b7SJoseph Chen 		check = (struct sysmem_check *)
152*ffa8f8b7SJoseph Chen 				(prop->base + prop->size - sizeof(*check));
153*ffa8f8b7SJoseph Chen 		if (check->magic != SYSMEM_MAGIC) {
154*ffa8f8b7SJoseph Chen 			ret = -EOVERFLOW;
155*ffa8f8b7SJoseph Chen 			SYSMEM_E("\"%s\" (base=0x%08lx, size=0x%lx) is Overflow!\n",
156*ffa8f8b7SJoseph Chen 				 prop->name, (ulong)prop->base, (ulong)prop->size);
157*ffa8f8b7SJoseph Chen 		}
158*ffa8f8b7SJoseph Chen 	}
159*ffa8f8b7SJoseph Chen 
160*ffa8f8b7SJoseph Chen 	/* Check stack */
161*ffa8f8b7SJoseph Chen 	check = (struct sysmem_check *)(gd->start_addr_sp - CONFIG_SYS_STACK_SIZE);
162*ffa8f8b7SJoseph Chen 	if (check->magic != SYSMEM_MAGIC) {
163*ffa8f8b7SJoseph Chen 		ret = -EOVERFLOW;
164*ffa8f8b7SJoseph Chen 		SYSMEM_E("Runtime stack is Overflow!\n");
165*ffa8f8b7SJoseph Chen 	}
166*ffa8f8b7SJoseph Chen 
167*ffa8f8b7SJoseph Chen 	return ret;
168*ffa8f8b7SJoseph Chen }
169*ffa8f8b7SJoseph Chen 
170*ffa8f8b7SJoseph Chen int sysmem_dump_check(void)
171*ffa8f8b7SJoseph Chen {
172*ffa8f8b7SJoseph Chen 	sysmem_dump();
173*ffa8f8b7SJoseph Chen 
174*ffa8f8b7SJoseph Chen 	return sysmem_check();
175*ffa8f8b7SJoseph Chen }
176*ffa8f8b7SJoseph Chen 
177*ffa8f8b7SJoseph Chen static int sysmem_is_overlap(phys_addr_t base1, phys_size_t size1,
178*ffa8f8b7SJoseph Chen 			     phys_addr_t base2, phys_size_t size2)
179*ffa8f8b7SJoseph Chen {
180*ffa8f8b7SJoseph Chen 	return ((base1 < (base2 + size2)) && (base2 < (base1 + size1)));
181*ffa8f8b7SJoseph Chen }
182*ffa8f8b7SJoseph Chen 
183*ffa8f8b7SJoseph Chen int sysmem_add(phys_addr_t base, phys_size_t size)
184*ffa8f8b7SJoseph Chen {
185*ffa8f8b7SJoseph Chen 	struct sysmem *sysmem = &plat_sysmem;
186*ffa8f8b7SJoseph Chen 	int ret;
187*ffa8f8b7SJoseph Chen 
188*ffa8f8b7SJoseph Chen 	if (!sysmem_has_init())
189*ffa8f8b7SJoseph Chen 		return -ENOSYS;
190*ffa8f8b7SJoseph Chen 
191*ffa8f8b7SJoseph Chen 	ret = lmb_add(&sysmem->lmb, base, size);
192*ffa8f8b7SJoseph Chen 	if (ret < 0)
193*ffa8f8b7SJoseph Chen 		SYSMEM_E("Failed to add sysmem at 0x%lx for 0x%lx size\n",
194*ffa8f8b7SJoseph Chen 			 (ulong)base, (ulong)size);
195*ffa8f8b7SJoseph Chen 
196*ffa8f8b7SJoseph Chen 	return (ret >= 0) ? 0 : ret;
197*ffa8f8b7SJoseph Chen }
198*ffa8f8b7SJoseph Chen 
199*ffa8f8b7SJoseph Chen int sysmem_reserve(const char *name, phys_addr_t base, phys_size_t size)
200*ffa8f8b7SJoseph Chen {
201*ffa8f8b7SJoseph Chen 	struct sysmem *sysmem = &plat_sysmem;
202*ffa8f8b7SJoseph Chen 	struct sysmem_property *prop;
203*ffa8f8b7SJoseph Chen 	struct list_head *node;
204*ffa8f8b7SJoseph Chen 	int ret = 0;
205*ffa8f8b7SJoseph Chen 
206*ffa8f8b7SJoseph Chen 	if (!sysmem_has_init())
207*ffa8f8b7SJoseph Chen 		return -ENOSYS;
208*ffa8f8b7SJoseph Chen 
209*ffa8f8b7SJoseph Chen 	if (!name) {
210*ffa8f8b7SJoseph Chen 		SYSMEM_E("NULL name for reserved sysmem\n");
211*ffa8f8b7SJoseph Chen 		return -EINVAL;
212*ffa8f8b7SJoseph Chen 	}
213*ffa8f8b7SJoseph Chen 
214*ffa8f8b7SJoseph Chen 	/* Check overlap */
215*ffa8f8b7SJoseph Chen 	list_for_each(node, &sysmem->reserved_head) {
216*ffa8f8b7SJoseph Chen 		prop = list_entry(node, struct sysmem_property, node);
217*ffa8f8b7SJoseph Chen 		if (!strcmp(prop->name, name)) {
218*ffa8f8b7SJoseph Chen 			SYSMEM_E("Failed to double reserve for existence \"%s\"\n", name);
219*ffa8f8b7SJoseph Chen 			return -EEXIST;
220*ffa8f8b7SJoseph Chen 		} else if (sysmem_is_overlap(prop->base, prop->size, base, size)) {
221*ffa8f8b7SJoseph Chen 			SYSMEM_W("\"%s\" (base=0x%08lx, size=0x%lx) reserve is "
222*ffa8f8b7SJoseph Chen 				 "overlap with existence \"%s\" (base=0x%08lx, size=0x%lx)\n",
223*ffa8f8b7SJoseph Chen 				 name, (ulong)base, (ulong)size, prop->name,
224*ffa8f8b7SJoseph Chen 				 (ulong)prop->base, (ulong)prop->size);
225*ffa8f8b7SJoseph Chen 		}
226*ffa8f8b7SJoseph Chen 	}
227*ffa8f8b7SJoseph Chen 
228*ffa8f8b7SJoseph Chen 	ret = lmb_reserve(&sysmem->lmb, base, size);
229*ffa8f8b7SJoseph Chen 	if (ret >= 0) {
230*ffa8f8b7SJoseph Chen 		prop = malloc(sizeof(*prop));
231*ffa8f8b7SJoseph Chen 		if (!prop) {
232*ffa8f8b7SJoseph Chen 			SYSMEM_E("No memory for \"%s\" reserve sysmem\n", name);
233*ffa8f8b7SJoseph Chen 			return -ENOMEM;
234*ffa8f8b7SJoseph Chen 		}
235*ffa8f8b7SJoseph Chen 
236*ffa8f8b7SJoseph Chen 		prop->name = name;
237*ffa8f8b7SJoseph Chen 		prop->base = base;
238*ffa8f8b7SJoseph Chen 		prop->size = size;
239*ffa8f8b7SJoseph Chen 		list_add_tail(&prop->node, &sysmem->reserved_head);
240*ffa8f8b7SJoseph Chen 	} else {
241*ffa8f8b7SJoseph Chen 		SYSMEM_E("Failed to reserve \"%s\" at 0x%lx\n", name, (ulong)base);
242*ffa8f8b7SJoseph Chen 		return -EINVAL;
243*ffa8f8b7SJoseph Chen 	}
244*ffa8f8b7SJoseph Chen 
245*ffa8f8b7SJoseph Chen 	return 0;
246*ffa8f8b7SJoseph Chen }
247*ffa8f8b7SJoseph Chen 
248*ffa8f8b7SJoseph Chen void *sysmem_alloc_align_base(const char *name,
249*ffa8f8b7SJoseph Chen 			      phys_addr_t base,
250*ffa8f8b7SJoseph Chen 			      phys_size_t size,
251*ffa8f8b7SJoseph Chen 			      ulong align)
252*ffa8f8b7SJoseph Chen {
253*ffa8f8b7SJoseph Chen 	struct sysmem *sysmem = &plat_sysmem;
254*ffa8f8b7SJoseph Chen 	struct sysmem_property *prop;
255*ffa8f8b7SJoseph Chen 	struct sysmem_check *check;
256*ffa8f8b7SJoseph Chen 	struct list_head *node;
257*ffa8f8b7SJoseph Chen 	phys_addr_t paddr;
258*ffa8f8b7SJoseph Chen 	phys_addr_t alloc_base;
259*ffa8f8b7SJoseph Chen 	phys_size_t alloc_size;
260*ffa8f8b7SJoseph Chen 
261*ffa8f8b7SJoseph Chen 	if (!sysmem_has_init())
262*ffa8f8b7SJoseph Chen 		return NULL;
263*ffa8f8b7SJoseph Chen 
264*ffa8f8b7SJoseph Chen 	if (!name) {
265*ffa8f8b7SJoseph Chen 		SYSMEM_E("NULL name for alloc sysmem\n");
266*ffa8f8b7SJoseph Chen 		return NULL;
267*ffa8f8b7SJoseph Chen 	}
268*ffa8f8b7SJoseph Chen 
269*ffa8f8b7SJoseph Chen 	/* Already allocated ? */
270*ffa8f8b7SJoseph Chen 	list_for_each(node, &sysmem->allocated_head) {
271*ffa8f8b7SJoseph Chen 		prop = list_entry(node, struct sysmem_property, node);
272*ffa8f8b7SJoseph Chen 		if (!strcmp(prop->name, name)) {
273*ffa8f8b7SJoseph Chen 			SYSMEM_E("Failed to double alloc for existence \"%s\"\n", name);
274*ffa8f8b7SJoseph Chen 			return NULL;
275*ffa8f8b7SJoseph Chen 		} else if (sysmem_is_overlap(prop->base, prop->size, base, size)) {
276*ffa8f8b7SJoseph Chen 			SYSMEM_E("\"%s\" (base=0x%08lx, size=0x%lx) alloc is "
277*ffa8f8b7SJoseph Chen 				 "overlap with existence \"%s\" (base=0x%08lx, size=0x%lx)\n",
278*ffa8f8b7SJoseph Chen 				 name, (ulong)base, (ulong)size,
279*ffa8f8b7SJoseph Chen 				 prop->name, (ulong)prop->base,
280*ffa8f8b7SJoseph Chen 				 (ulong)prop->size);
281*ffa8f8b7SJoseph Chen 			return NULL;
282*ffa8f8b7SJoseph Chen 		}
283*ffa8f8b7SJoseph Chen 	}
284*ffa8f8b7SJoseph Chen 
285*ffa8f8b7SJoseph Chen 	alloc_size = size + sizeof(*check);
286*ffa8f8b7SJoseph Chen 	if (base == SYSMEM_ALLOC_ANYWHERE)
287*ffa8f8b7SJoseph Chen 		alloc_base = base;
288*ffa8f8b7SJoseph Chen 	else
289*ffa8f8b7SJoseph Chen 		alloc_base = base + alloc_size;	/* LMB is align down alloc mechanism */
290*ffa8f8b7SJoseph Chen 
291*ffa8f8b7SJoseph Chen 	paddr = lmb_alloc_base(&sysmem->lmb, alloc_size, align, alloc_base);
292*ffa8f8b7SJoseph Chen 	if (paddr) {
293*ffa8f8b7SJoseph Chen 		if  ((paddr == base) || (base == SYSMEM_ALLOC_ANYWHERE)) {
294*ffa8f8b7SJoseph Chen 			prop = malloc(sizeof(*prop));
295*ffa8f8b7SJoseph Chen 			if (!prop) {
296*ffa8f8b7SJoseph Chen 				SYSMEM_E("No memory for \"%s\" alloc sysmem\n", name);
297*ffa8f8b7SJoseph Chen 				return NULL;
298*ffa8f8b7SJoseph Chen 			}
299*ffa8f8b7SJoseph Chen 
300*ffa8f8b7SJoseph Chen 			prop->name = name;
301*ffa8f8b7SJoseph Chen 			prop->base = paddr;
302*ffa8f8b7SJoseph Chen 			prop->size = alloc_size;
303*ffa8f8b7SJoseph Chen 			sysmem->allocated_cnt++;
304*ffa8f8b7SJoseph Chen 
305*ffa8f8b7SJoseph Chen 			check = (struct sysmem_check *)(paddr + size);
306*ffa8f8b7SJoseph Chen 			check->magic = SYSMEM_MAGIC;
307*ffa8f8b7SJoseph Chen 
308*ffa8f8b7SJoseph Chen 			list_add_tail(&prop->node, &sysmem->allocated_head);
309*ffa8f8b7SJoseph Chen 		} else {
310*ffa8f8b7SJoseph Chen 			SYSMEM_E("Failed to alloc \"%s\" at expect 0x%lx but "
311*ffa8f8b7SJoseph Chen 				 "alloc at 0x%lx\n",
312*ffa8f8b7SJoseph Chen 				 name, (ulong)base, (ulong)paddr);
313*ffa8f8b7SJoseph Chen 			return NULL;
314*ffa8f8b7SJoseph Chen 		}
315*ffa8f8b7SJoseph Chen 	} else {
316*ffa8f8b7SJoseph Chen 		SYSMEM_E("Failed to alloc \"%s\" at 0x%lx\n", name, (ulong)base);
317*ffa8f8b7SJoseph Chen 	}
318*ffa8f8b7SJoseph Chen 
319*ffa8f8b7SJoseph Chen 	SYSMEM_D("Alloc: \"%s\", paddr=0x%lx, size=0x%lx, align=0x%x, anywhere=%d\n",
320*ffa8f8b7SJoseph Chen 		 name, (ulong)paddr, (ulong)size, (u32)align, !base);
321*ffa8f8b7SJoseph Chen 
322*ffa8f8b7SJoseph Chen 	return (void *)paddr;
323*ffa8f8b7SJoseph Chen }
324*ffa8f8b7SJoseph Chen 
325*ffa8f8b7SJoseph Chen void *sysmem_alloc_align(const char *name, phys_size_t size, ulong align)
326*ffa8f8b7SJoseph Chen {
327*ffa8f8b7SJoseph Chen 	return sysmem_alloc_align_base(name,
328*ffa8f8b7SJoseph Chen 				       SYSMEM_ALLOC_ANYWHERE,
329*ffa8f8b7SJoseph Chen 				       size,
330*ffa8f8b7SJoseph Chen 				       align);
331*ffa8f8b7SJoseph Chen }
332*ffa8f8b7SJoseph Chen 
333*ffa8f8b7SJoseph Chen void *sysmem_alloc_base(const char *name, phys_addr_t base, phys_size_t size)
334*ffa8f8b7SJoseph Chen {
335*ffa8f8b7SJoseph Chen 	return sysmem_alloc_align_base(name,
336*ffa8f8b7SJoseph Chen 				       base,
337*ffa8f8b7SJoseph Chen 				       size,
338*ffa8f8b7SJoseph Chen 				       SYSMEM_ALLOC_NO_ALIGN);
339*ffa8f8b7SJoseph Chen }
340*ffa8f8b7SJoseph Chen 
341*ffa8f8b7SJoseph Chen void *sysmem_alloc(const char *name, phys_size_t size)
342*ffa8f8b7SJoseph Chen {
343*ffa8f8b7SJoseph Chen 	return sysmem_alloc_align_base(name,
344*ffa8f8b7SJoseph Chen 				       SYSMEM_ALLOC_ANYWHERE,
345*ffa8f8b7SJoseph Chen 				       size,
346*ffa8f8b7SJoseph Chen 				       SYSMEM_ALLOC_NO_ALIGN);
347*ffa8f8b7SJoseph Chen }
348*ffa8f8b7SJoseph Chen 
349*ffa8f8b7SJoseph Chen int sysmem_free(phys_addr_t base)
350*ffa8f8b7SJoseph Chen {
351*ffa8f8b7SJoseph Chen 	struct sysmem *sysmem = &plat_sysmem;
352*ffa8f8b7SJoseph Chen 	struct sysmem_property *prop;
353*ffa8f8b7SJoseph Chen 	struct list_head *node;
354*ffa8f8b7SJoseph Chen 	int found = 0;
355*ffa8f8b7SJoseph Chen 	int ret;
356*ffa8f8b7SJoseph Chen 
357*ffa8f8b7SJoseph Chen 	if (!sysmem_has_init())
358*ffa8f8b7SJoseph Chen 		return -ENOSYS;
359*ffa8f8b7SJoseph Chen 
360*ffa8f8b7SJoseph Chen 	/* Find existence */
361*ffa8f8b7SJoseph Chen 	list_for_each(node, &sysmem->allocated_head) {
362*ffa8f8b7SJoseph Chen 		prop = list_entry(node, struct sysmem_property, node);
363*ffa8f8b7SJoseph Chen 		if (prop->base == base) {
364*ffa8f8b7SJoseph Chen 			found = 1;
365*ffa8f8b7SJoseph Chen 			break;
366*ffa8f8b7SJoseph Chen 		}
367*ffa8f8b7SJoseph Chen 	}
368*ffa8f8b7SJoseph Chen 
369*ffa8f8b7SJoseph Chen 	if (!found) {
370*ffa8f8b7SJoseph Chen 		SYSMEM_E("Failed to free no allocated sysmem at 0x%lx\n", (ulong)base);
371*ffa8f8b7SJoseph Chen 		return -EINVAL;
372*ffa8f8b7SJoseph Chen 	}
373*ffa8f8b7SJoseph Chen 
374*ffa8f8b7SJoseph Chen 	ret = lmb_free(&sysmem->lmb, prop->base, prop->size);
375*ffa8f8b7SJoseph Chen 	if (ret >= 0) {
376*ffa8f8b7SJoseph Chen 		SYSMEM_I("Free: \"%s\", paddr=0x%lx, size=0x%lx\n",
377*ffa8f8b7SJoseph Chen 			 prop->name, (ulong)prop->base, (ulong)prop->size);
378*ffa8f8b7SJoseph Chen 		sysmem->allocated_cnt--;
379*ffa8f8b7SJoseph Chen 		list_del(&prop->node);
380*ffa8f8b7SJoseph Chen 		free(prop);
381*ffa8f8b7SJoseph Chen 	} else {
382*ffa8f8b7SJoseph Chen 		SYSMEM_E("Failed to free \"%s\" at 0x%lx\n", prop->name, (ulong)base);
383*ffa8f8b7SJoseph Chen 	}
384*ffa8f8b7SJoseph Chen 
385*ffa8f8b7SJoseph Chen 	return (ret >= 0) ? 0 : ret;
386*ffa8f8b7SJoseph Chen }
387*ffa8f8b7SJoseph Chen 
388*ffa8f8b7SJoseph Chen int sysmem_init(void)
389*ffa8f8b7SJoseph Chen {
390*ffa8f8b7SJoseph Chen 	struct sysmem *sysmem = &plat_sysmem;
391*ffa8f8b7SJoseph Chen 	struct sysmem_check *check;
392*ffa8f8b7SJoseph Chen 	phys_addr_t mem_start;
393*ffa8f8b7SJoseph Chen 	phys_size_t mem_size;
394*ffa8f8b7SJoseph Chen 	int ret;
395*ffa8f8b7SJoseph Chen 
396*ffa8f8b7SJoseph Chen 	SYSMEM_I("init\n");
397*ffa8f8b7SJoseph Chen 
398*ffa8f8b7SJoseph Chen 	lmb_init(&sysmem->lmb);
399*ffa8f8b7SJoseph Chen 	INIT_LIST_HEAD(&sysmem->allocated_head);
400*ffa8f8b7SJoseph Chen 	INIT_LIST_HEAD(&sysmem->reserved_head);
401*ffa8f8b7SJoseph Chen 	sysmem->allocated_cnt = 0;
402*ffa8f8b7SJoseph Chen 	sysmem->has_init = true;
403*ffa8f8b7SJoseph Chen 
404*ffa8f8b7SJoseph Chen 	/* Add all available system memory */
405*ffa8f8b7SJoseph Chen #ifdef CONFIG_NR_DRAM_BANKS
406*ffa8f8b7SJoseph Chen 	int i;
407*ffa8f8b7SJoseph Chen 
408*ffa8f8b7SJoseph Chen 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
409*ffa8f8b7SJoseph Chen 		ret = sysmem_add(gd->bd->bi_dram[i].start,
410*ffa8f8b7SJoseph Chen 				 gd->bd->bi_dram[i].size);
411*ffa8f8b7SJoseph Chen 		if (ret) {
412*ffa8f8b7SJoseph Chen 			SYSMEM_E("Failed to add sysmem from bi_dram[%d]\n", i);
413*ffa8f8b7SJoseph Chen 			return ret;
414*ffa8f8b7SJoseph Chen 		}
415*ffa8f8b7SJoseph Chen 	}
416*ffa8f8b7SJoseph Chen #else
417*ffa8f8b7SJoseph Chen 	mem_start = env_get_bootm_low();
418*ffa8f8b7SJoseph Chen 	mem_size = env_get_bootm_size();
419*ffa8f8b7SJoseph Chen 	ret = sysmem_add(mem_start, mem_size);
420*ffa8f8b7SJoseph Chen 	if (ret) {
421*ffa8f8b7SJoseph Chen 		SYSMEM_E("Failed to add sysmem from bootm_low/size\n");
422*ffa8f8b7SJoseph Chen 		return ret;
423*ffa8f8b7SJoseph Chen 	}
424*ffa8f8b7SJoseph Chen #endif
425*ffa8f8b7SJoseph Chen 
426*ffa8f8b7SJoseph Chen 	/* Reserved for arch */
427*ffa8f8b7SJoseph Chen 	ret = arch_sysmem_reserve(sysmem);
428*ffa8f8b7SJoseph Chen 	if (ret) {
429*ffa8f8b7SJoseph Chen 		SYSMEM_E("Failed to reserve sysmem for arch\n");
430*ffa8f8b7SJoseph Chen 		return ret;
431*ffa8f8b7SJoseph Chen 	}
432*ffa8f8b7SJoseph Chen 
433*ffa8f8b7SJoseph Chen 	/* Reserved for board */
434*ffa8f8b7SJoseph Chen 	ret = board_sysmem_reserve(sysmem);
435*ffa8f8b7SJoseph Chen 	if (ret) {
436*ffa8f8b7SJoseph Chen 		SYSMEM_E("Failed to reserve sysmem for board\n");
437*ffa8f8b7SJoseph Chen 		return ret;
438*ffa8f8b7SJoseph Chen 	}
439*ffa8f8b7SJoseph Chen 
440*ffa8f8b7SJoseph Chen 	/* Reserved for U-boot framework 'reserve_xxx()' */
441*ffa8f8b7SJoseph Chen 	mem_start = gd->start_addr_sp - CONFIG_SYS_STACK_SIZE;
442*ffa8f8b7SJoseph Chen 	mem_size = gd->ram_top - mem_start;
443*ffa8f8b7SJoseph Chen 	check = (struct sysmem_check *)mem_start;
444*ffa8f8b7SJoseph Chen 	check->magic = SYSMEM_MAGIC;
445*ffa8f8b7SJoseph Chen 
446*ffa8f8b7SJoseph Chen 	ret = sysmem_reserve("U-Boot", mem_start, mem_size);
447*ffa8f8b7SJoseph Chen 	if (ret) {
448*ffa8f8b7SJoseph Chen 		SYSMEM_E("Failed to reserve sysmem for U-Boot framework\n");
449*ffa8f8b7SJoseph Chen 		return ret;
450*ffa8f8b7SJoseph Chen 	}
451*ffa8f8b7SJoseph Chen 
452*ffa8f8b7SJoseph Chen 	sysmem_dump();
453*ffa8f8b7SJoseph Chen 
454*ffa8f8b7SJoseph Chen 	return 0;
455*ffa8f8b7SJoseph Chen }
456*ffa8f8b7SJoseph Chen 
457*ffa8f8b7SJoseph Chen __weak int board_sysmem_reserve(struct sysmem *sysmem)
458*ffa8f8b7SJoseph Chen {
459*ffa8f8b7SJoseph Chen 	/* please define platform specific board_sysmem_reserve() */
460*ffa8f8b7SJoseph Chen 	return 0;
461*ffa8f8b7SJoseph Chen }
462*ffa8f8b7SJoseph Chen 
463*ffa8f8b7SJoseph Chen __weak int arch_sysmem_reserve(struct sysmem *sysmem)
464*ffa8f8b7SJoseph Chen {
465*ffa8f8b7SJoseph Chen 	/* please define platform specific arch_sysmem_reserve() */
466*ffa8f8b7SJoseph Chen 	return 0;
467*ffa8f8b7SJoseph Chen }
468