summaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/sama5/sam_allocateheap.c
blob: 2147895157c7e07559a01c3d1d25416e53ef498a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
/****************************************************************************
 * arch/arm/src/sama5/sam_allocateheap.c
 *
 *   Copyright (C) 2013, 2015 Gregory Nutt. All rights reserved.
 *   Author: Gregory Nutt <gnutt@nuttx.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name NuttX nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <sys/types.h>
#include <stdint.h>
#include <assert.h>
#include <debug.h>

#include <nuttx/arch.h>
#include <nuttx/board.h>
#include <nuttx/kmalloc.h>

#include <arch/board/board.h>

#include "chip.h"
#include "up_arch.h"
#include "up_internal.h"
#include "mmu.h"

/****************************************************************************
 * Private Definitions
 ****************************************************************************/
/* Configuration ************************************************************/
/* Terminology.  In the flat build (CONFIG_BUILD_FLAT=y), there is only a
 * single heap access with the standard allocations (malloc/free).  This
 * heap is referred to as the user heap.  In the protected build
 * (CONFIG_BUILD_PROTECTED=y) where an MPU is used to protect a region of
 * otherwise flat memory, there will be two allocators:  One that allocates
 * protected (kernel) memory and one that allocates unprotected (user)
 * memory.  These are referred to as the kernel and user heaps,
 * respectively.
 *
 * The ARMv7 has no MPU but does have an MMU.  With this MMU, it can support
 * the kernel build (CONFIG_BUILD_KERNEL=y).  In this configuration, there
 * is one kernel heap but multiple user heaps:  One per task group.  However,
 * in this case, we need only be concerned about initializing the single
 * kernel heap here.
 */

#if defined(CONFIG_BUILD_KERNEL)
#  define MM_ADDREGION kmm_addregion
#else
#  define MM_ADDREGION umm_addregion
#endif

/* The Primary Heap *********************************************************/
/* The physical address of the primary heap is defined by CONFIG_RAM_START,
 * CONFIG_RAM_SIZE, and CONFIG_RAM_END where:
 *
 *   CONFIG_RAM_END = CONFIG_RAM_START + CONFIG_RAM_SIZE
 *
 * and the corresponding virtual address are give by:
 *
 *   CONFIG_RAM_VEND = CONFIG_RAM_VSTART + CONFIG_RAM_SIZE
 *
 * CONFIG_RAM_VSTART is the usable beginning of the RAM region.  The "usable"
 * start would exclude, for example, any memory at the bottom of the RAM
 * region used for the 16KB page table.  If we are also executing from this
 * same RAM region then CONFIG_RAM_START is not used.  Instead, the value of
 * g_idle_stack is the used; this variable holds the first available byte of
 * memory after the .text, .data, .bss, and IDLE stack allocations.
 *
 * CONFIG_RAM_VEND is defined in the configuration it is the usable top of
 * the RAM region beginning at CONFIG_RAM_START.  The "usable" top would
 * exclude, for example, any memory reserved at the top of the for the 16KB
 * page table.
 *
 * A special may occur when we execute from DRAM.  In that case,
 * CONFIG_RAM_VSTART must be set to the (virtual) start of DRAM and
 * CONFIG_RAM_SIZE must be set to the size of the DRAM.  These settings are
 * necessary to provide the DRAM MMU mappings when the system boots and, by
 * default, the DRAM memory will be added to the heap all the way up to
 * CONFIG_RAM_VEND
 *
 * However, there are certain cases where you may want to reserve a block of
 * DRAM for other purposes such a large DMA buffer or an LCD framebuffer.
 * In those cases, the CONFIG_SAMA5_DDRCS_RESERVE can select a different end
 * of the DRAM memory to add to the heap.  If CONFIG_SAMA5_DDRCS_RESERVE is
 * selected, then the setting CONFIG_SAMA5_DDRCS_HEAP_END provides the end
 * (plus one) (virtual) address of memory to be added to the heap; DRAM after
 * this address will not be part of the heap and so will be available for
 * other purposes
 *
 *   NOTE: There is way to reserve memory before the start of the program
 *   in DRAM using this mechanism.  That configuration is possible, but
 *   not using this configuration setting.
 */

/* Memory Regions ***********************************************************/
/* Check if we have been asked to reserve memory at the end of the primary
 * memory region.  This option is only available if we are executing from
 * DRAM and only if CONFIG_SAMA5_DDRCS_RESERVE is selected.
 */

#ifdef CONFIG_SAMA5_DDRCS_RESERVE

  /* CONFIG_SAMA5_DDRCS_HEAP_END specifies the end (plus one) of the DRAM
   * to add to the heap.  Memory starting at CONFIG_SAMA5_DDRCS_HEAP_END
   * and extending to CONFIG_RAM_VEND is then available for other purposes.
   */

#  if !defined(CONFIG_SAMA5_DDRCS_HEAP_END)
#    error CONFIG_SAMA5_DDRCS_HEAP_END must be defined in this configuration
#  elif CONFIG_SAMA5_DDRCS_HEAP_END > CONFIG_RAM_VEND
#    error CONFIG_SAMA5_DDRCS_HEAP_END is beyond CONFIG_RAM_VEND
#  elif CONFIG_SAMA5_DDRCS_HEAP_END < CONFIG_RAM_VSTART
#    error CONFIG_SAMA5_DDRCS_HEAP_END is before CONFIG_RAM_VSTART
# endif

#  define SAMA5_PRIMARY_HEAP_END CONFIG_SAMA5_DDRCS_HEAP_END
#else
  /* Otherwise, add the RAM all the way to the the end of the primary memory
   * region to the heap.
   */

#  define SAMA5_PRIMARY_HEAP_END CONFIG_RAM_VEND
#endif

/* We cannot use the memory for heap if it is not enabled.  Or, if it is
 * enabled, but does not hold SDRAM, SRAM, or PSRAM.
 *
 * We cannot add the region if it is if we are executing from it!  In that
 * case, the remainder of the memory will automatically be added to the heap
 * based on g_idle_topstack and SAMA5_PRIMARY_HEAP_END.
 */

#if defined(CONFIG_SAMA5_BOOT_ISRAM)
#  undef CONFIG_SAMA5_ISRAM_HEAP
#endif

#if !defined(CONFIG_SAMA5_DDRCS) || defined(CONFIG_SAMA5_BOOT_SDRAM) || \
    defined(CONFIG_BOOT_SDRAM_DATA)
#  undef CONFIG_SAMA5_DDRCS_HEAP
#endif

#if !defined(CONFIG_SAMA5_EBICS0) || defined(CONFIG_SAMA5_BOOT_CS0SRAM) || \
   (!defined(CONFIG_SAMA5_EBICS0_SRAM) && !defined(CONFIG_SAMA5_EBICS0_PSRAM))

#  undef SAMA5_EBICS0_HEAP
#endif

#if !defined(CONFIG_SAMA5_EBICS1) || defined(CONFIG_SAMA5_BOOT_CS1SRAM) || \
   (!defined(CONFIG_SAMA5_EBICS1_SRAM) && !defined(CONFIG_SAMA5_EBICS1_PSRAM))

#  undef SAMA5_EBICS1_HEAP
#endif

#if !defined(CONFIG_SAMA5_EBICS2) || defined(CONFIG_SAMA5_BOOT_CS2SRAM) || \
   (!defined(CONFIG_SAMA5_EBICS2_SRAM) && !defined(CONFIG_SAMA5_EBICS2_PSRAM))

#  undef SAMA5_EBICS2_HEAP
#endif

#if !defined(SAMA5_CONFIG_EBICS3) || defined(CONFIG_SAMA5_BOOT_CS3SRAM) || \
   (!defined(SAMA5_CONFIG_EBICS3_SRAM) && !defined(CONFIG_SAMA5_EBICS3_PSRAM))

#  undef SAMA5_EBICS3_HEAP
#endif

/* The heap space in the primary memory region is added automatically when
 * up_allocate_heap is called.  So if the memory region is the primary region,
 * it should not be added to the heap (again).
 */

#if (CONFIG_RAM_VSTART & 0xfff00000) == SAM_ISRAM0_VADDR
#  undef CONFIG_SAMA5_ISRAM_HEAP
#endif

#if (CONFIG_RAM_VSTART & 0xfff00000) == SAM_DDRCS_VSECTION
#  undef CONFIG_SAMA5_DDRCS_HEAP
#endif

#if (CONFIG_RAM_VSTART & 0xfff00000) == SAM_EBICS0_VSECTION
#  undef SAMA5_EBICS0_HEAP
#endif

#if (CONFIG_RAM_VSTART & 0xfff00000) == SAM_EBICS1_VSECTION
#  undef SAMA5_EBICS1_HEAP
#endif

#if (CONFIG_RAM_VSTART & 0xfff00000) == SAM_EBICS2_VSECTION
#  undef SAMA5_EBICS2_HEAP
#endif

#if (CONFIG_RAM_VSTART & 0xfff00000) == SAM_EBICS3_VSECTION
#  undef SAMA5_EBICS3_HEAP
#endif

/****************************************************************************
 * Private Data
 ****************************************************************************/

/****************************************************************************
 * Private Functions
 ****************************************************************************/

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: up_allocate_heap/up_allocate_kheap
 *
 * Description:
 *   This function will be called to dynamically set aside the heap region.
 *   For the flat build, this heap is referred to as the user heap (for
 *   compatibility with other platforms).  For the kernel build
 *   (CONFIG_BUILD_KERNEL=y) this is referred to a the kernel heap.
 *
 ****************************************************************************/

#if defined(CONFIG_BUILD_KERNEL)
void up_allocate_kheap(FAR void **heap_start, size_t *heap_size)
#else
void up_allocate_heap(FAR void **heap_start, size_t *heap_size)
#endif
{
#if defined(CONFIG_BOOT_SDRAM_DATA)
  /* In this case, the IDLE stack is in ISRAM, but data is in SDRAM.  The
   * heap is at the end of BSS through the configured end of SDRAM.
   */

  board_led_on(LED_HEAPALLOCATE);
  *heap_start = (FAR void*)&_ebss;
  *heap_size  = SAMA5_PRIMARY_HEAP_END - (size_t)&_ebss;

#else
  /* Both data and the heap are in ISRAM.  The heap is then from the end of
   * IDLE stack through the configured end of ISRAM.
   */

  board_led_on(LED_HEAPALLOCATE);
  *heap_start = (FAR void*)g_idle_topstack;
  *heap_size  = SAMA5_PRIMARY_HEAP_END - g_idle_topstack;
#endif
}

/****************************************************************************
 * Name: up_addregion
 *
 * Description:
 *   Memory may be added in non-contiguous chunks.  Additional chunks are
 *   added by calling this function.
 *
 ****************************************************************************/

#if CONFIG_MM_REGIONS > 1
void up_addregion(void)
{
  int nregions = CONFIG_MM_REGIONS - 1;
  uintptr_t vaddr;
  size_t size;

#ifdef CONFIG_SAMA5_ISRAM_HEAP
  vaddr = (uintptr_t)SAM_ISRAM0_VADDR
  size  = SAM_ISRAM0_SIZE + SAM_ISRAM1_SIZE;

  /* Add the ISRAM user heap region. */

  MM_ADDREGION((void *)vaddr, size);
  nregions--;
#endif

#ifdef CONFIG_SAMA5_DDRCS_HEAP
  if (nregions > 0)
    {
      vaddr = (uintptr_t)SAM_DDRCS_VSECTION + SAMA5_DDRCS_HEAP_OFFSET;
      size  = SAMA5_DDRCS_HEAP_SIZE;

      /* Add the DDR-SDRAM user heap region. */

      MM_ADDREGION((void *)vaddr, size);
      nregions--;
    }
  else
    {
      lldbg("ERROR: SDRAM memory not added to heap.  CONFIG_MM_NREGIONS=%d\n",
            CONFIG_MM_REGIONS);
      lldbg("       Increase the size of CONFIG_MM_NREGIONS\n");
    }
#endif

#ifdef SAMA5_EBICS0_HEAP
  if (nregions > 0)
    {
      vaddr = (uintptr_t)SAM_EBICS0_VSECTION + SAMA5_EBICS0_HEAP_OFFSET;
      size  = SAMA5_EBICS0_HEAP_SIZE;

      /* Add the EBICS0 user heap region. */

      MM_ADDREGION((void *)vaddr, size);
      nregions--;
    }
  else
    {
      lldbg("ERROR: CS0 memory not added to heap.  CONFIG_MM_NREGIONS=%d\n",
            CONFIG_MM_REGIONS);
      lldbg("       Increase the size of CONFIG_MM_NREGIONS\n");
    }
#endif

#ifdef SAMA5_EBICS1_HEAP
  if (nregions > 0)
    {
      vaddr = (uintptr_t)SAM_EBICS1_VSECTION + SAMA5_EBICS1_HEAP_OFFSET;
      size  = SAMA5_EBICS1_HEAP_SIZE;

      /* Add the EBICS1 user heap region. */

      MM_ADDREGION((void *)vaddr, size);
      nregions--;
    }
  else
    {
      lldbg("ERROR: CS1 memory not added to heap.  CONFIG_MM_NREGIONS=%d\n",
            CONFIG_MM_REGIONS);
      lldbg("       Increase the size of CONFIG_MM_NREGIONS\n");
    }
#endif

#ifdef SAMA5_EBICS2_HEAP
  if (nregions > 0)
    {
      vaddr = (uintptr_t)SAM_EBICS2_VSECTION + SAMA5_EBICS2_HEAP_OFFSET;
      size  = SAMA5_EBICS2_HEAP_SIZE;

      /* Add the EBICS2 user heap region. */

      MM_ADDREGION((void *)vaddr, size);
      nregions--;
    }
  else
    {
      lldbg("ERROR: CS2 memory not added to heap.  CONFIG_MM_NREGIONS=%d\n",
            CONFIG_MM_REGIONS);
      lldbg("       Increase the size of CONFIG_MM_NREGIONS\n");
    }
#endif

#ifdef SAMA5_EBICS3_HEAP
  if (nregions > 0)
    {
      vaddr = (uintptr_t)SAM_EBICS3_VSECTION + SAMA5_EBICS3_HEAP_OFFSET;
      size  = SAMA5_EBICS3_HEAP_SIZE;

      /* Add the EBICS3 user heap region. */

      MM_ADDREGION(vaddr, size);
      nregions--;
    }
  else
    {
      lldbg("ERROR: CS3 memory not added to heap.  CONFIG_MM_NREGIONS=%d\n",
            CONFIG_MM_REGIONS);
      lldbg("       Increase the size of CONFIG_MM_NREGIONS\n");
    }
#endif

  /* Did we add all of the requestion regions */

  if (nregions > 0)
    {
      lldbg("ERROR: Not all regions added to heap: %d added, but CONFIG_MM_NREGIONS=%d\n",
            CONFIG_MM_REGIONS - nregions, CONFIG_MM_REGIONS);
      lldbg("       Decrease the size of CONFIG_MM_NREGIONS\n");
    }
}
#endif