1 #include <string.h>		// memset()
2 #include <psram_reserve.h>
3 #include <ameba_soc.h>
4 
5 static struct Psram_Heap g_Psram_heap;
6 
7 int g_Psram_heap_inited = 0;
8 static	_lock	Psram_heap_lock;
9 
10 #define configTOTAL_PSRAM_HEAP_SIZE		(0x200000)
11 #define configBYTE_PSRAM_ALIGNMENT			32
12 
13 PSRAM_HEAP_SECTION
14 static unsigned char psRAMHeap[configTOTAL_PSRAM_HEAP_SIZE];
15 
Psram_heap_init(void)16 void Psram_heap_init(void)
17 {
18 	/* Initialize heap with a single big chunk */
19 	g_Psram_heap.FreeList = (PsramMemChunk *)(psRAMHeap);
20 	g_Psram_heap.FreeList->next = NULL;
21 	g_Psram_heap.FreeList->size = configTOTAL_PSRAM_HEAP_SIZE;
22 
23 	g_Psram_heap_inited = 1;
24 
25 	rtw_spinlock_init(&Psram_heap_lock);
26 }
27 
28 /**
29   * @brief  allocate free memory from PSRAM.
30   * @param  size: size of the memory you want.
31   * @retval: header address of the memory allocated.
32   */
Psram_heap_allocmem(int size)33 void *Psram_heap_allocmem(int size)
34 {
35 	PsramMemChunk *chunk, *prev;
36 	struct Psram_Heap* h = &g_Psram_heap;
37 	_irqL 	irqL;
38 
39 	rtw_enter_critical(&Psram_heap_lock, &irqL);
40 
41 	if(!g_Psram_heap_inited)	Psram_heap_init();
42 
43 	/* Round size up to the allocation granularity */
44 	size = Psram_ROUND_UP2(size, configBYTE_PSRAM_ALIGNMENT);
45 
46 	/* Handle allocations of 0 bytes */
47 	if (!size)
48 		size = sizeof(PsramMemChunk);
49 
50 	/* Walk on the free list looking for any chunk big enough to
51 	 * fit the requested block size.
52 	 */
53 	for (prev = (PsramMemChunk *)&h->FreeList, chunk = h->FreeList;
54 		chunk;
55 		prev = chunk, chunk = chunk->next)
56 	{
57 		if (chunk->size >= size)
58 		{
59 			if (chunk->size == size)
60 			{
61 				/* Just remove this chunk from the free list */
62 				prev->next = chunk->next;
63 
64 				rtw_exit_critical(&Psram_heap_lock, &irqL);
65 
66 				return (void *)chunk;
67 			}
68 			else
69 			{
70 				/* Allocate from the END of an existing chunk */
71 				chunk->size -= size;
72 				void *result = (void *)((uint8_t *)chunk + chunk->size);
73 
74 				rtw_exit_critical(&Psram_heap_lock, &irqL);
75 
76 				return result;
77 			}
78 		}
79 	}
80 
81 	rtw_exit_critical(&Psram_heap_lock, &irqL);
82 
83 	return NULL; /* fail */
84 }
85 
86 
87 /**
88   * @brief  free memory in PSRAM.
89   * @param  mem: header address of the memory to be freed.
90   * @param  size: size of the memory.
91   * @retval none
92   */
Psram_reserved_heap_freemem(void * mem,int size)93 void Psram_reserved_heap_freemem(void *mem, int size)
94 {
95 	PsramMemChunk *prev;
96 	struct Psram_Heap* h = &g_Psram_heap;
97 	_irqL 	irqL;
98 
99 	rtw_enter_critical(&Psram_heap_lock, &irqL);
100 
101 	if(!g_Psram_heap_inited)	Psram_heap_init();
102 
103 	/* Round size up to the allocation granularity */
104 	size = Psram_ROUND_UP2(size, configBYTE_PSRAM_ALIGNMENT);
105 
106 	/* Handle allocations of 0 bytes */
107 	if (!size)
108 		size = sizeof(PsramMemChunk);
109 
110 	/* Special cases: first chunk in the free list or memory completely full */
111 	if (((uint8_t *)mem) < ((uint8_t *)h->FreeList) || !h->FreeList)
112 	{
113 		/* Insert memory block before the current free list head */
114 		prev = (PsramMemChunk *)mem;
115 		prev->next = h->FreeList;
116 		prev->size = size;
117 		h->FreeList = prev;
118 	}
119 	else /* Normal case: not the first chunk in the free list */
120 	{
121 		/*
122 		 * Walk on the free list. Stop at the insertion point (when mem
123 		 * is between prev and prev->next)
124 		 */
125 		prev = h->FreeList;
126 		while (prev->next < (PsramMemChunk *)mem && prev->next)
127 			prev = prev->next;
128 
129 		/* Should it be merged with previous block? */
130 		if (((uint8_t *)prev) + prev->size == ((uint8_t *)mem))
131 		{
132 			/* Yes */
133 			prev->size += size;
134 		}
135 		else /* not merged with previous chunk */
136 		{
137 			PsramMemChunk *curr = (PsramMemChunk*)mem;
138 
139 			/* insert it after the previous node
140 			 * and move the 'prev' pointer forward
141 			 * for the following operations
142 			 */
143 			curr->next = prev->next;
144 			curr->size = size;
145 			prev->next = curr;
146 
147 			/* Adjust for the following test */
148 			prev = curr;
149 		}
150 	}
151 
152 	/* Also merge with next chunk? */
153 	if (((uint8_t *)prev) + prev->size == ((uint8_t *)prev->next))
154 	{
155 		prev->size += prev->next->size;
156 		prev->next = prev->next->next;
157 	}
158 
159 	rtw_exit_critical(&Psram_heap_lock, &irqL);
160 }
161 
162 /**
163   * @brief  get the free memory size in PSRAM.
164   * @retval size of free momery in PSRAM.
165   */
Psram_reserve_free_size(void)166 int Psram_reserve_free_size(void)
167 {
168 	int free_mem = 0;
169 	struct Psram_Heap* h = &g_Psram_heap;
170 	_irqL 	irqL;
171 	PsramMemChunk *chunk;
172 
173 	rtw_enter_critical(&Psram_heap_lock, &irqL);
174 
175 	if(!g_Psram_heap_inited)	Psram_heap_init();
176 
177 	for (chunk = h->FreeList; chunk; chunk = chunk->next)
178 		free_mem += chunk->size;
179 
180 	rtw_exit_critical(&Psram_heap_lock, &irqL);
181 	return free_mem;
182 }
183 
184 /**
185   * @brief  allocate free memory from PSRAM.
186   * @param  size: size of the memory you want.
187   * @retval: header address of the memory allocated.
188   */
Psram_reserve_malloc(int size)189 void *Psram_reserve_malloc(int size)
190 {
191 	int *mem;
192 
193 	size += sizeof(int);
194 	if ((mem = (int*)Psram_heap_allocmem(size))){
195 		*mem++ = size;
196 	}
197 
198 	return (void *)mem;
199 }
200 
201 /**
202   * @brief allocate several continuous blocks of free memory from PSRAM.
203   * @param  num: num of blocks you want.
204   * @param  size: size of every block.
205   * @retval: header address of the memory allocated.
206   */
Psram_reserve_calloc(int num,int size)207 void *Psram_reserve_calloc(int num, int size)
208 {
209 	void *mem;
210 
211 	if ((mem = Psram_reserve_malloc(num * size)))
212 		memset(mem, 0, num * size);
213 
214 	return mem;
215 }
216 
217 /**
218   * @brief  free memory in PSRAM.
219   * @param  mem: header address of the memory to be freed.
220   * @retval none
221   */
Psram_reserve_free(void * mem)222 void Psram_reserve_free(void *mem)
223 {
224 	int *_mem = (int *)mem;
225 
226 	if (_mem)
227 	{
228 		--_mem;
229 		Psram_reserved_heap_freemem(_mem, *_mem);
230 	}
231 }
232 
233 
234