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